github.com/sevki/docker@v1.7.1/daemon/stats.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  
     7  	"github.com/docker/docker/api/types"
     8  	"github.com/docker/docker/daemon/execdriver"
     9  	"github.com/docker/libcontainer"
    10  	"github.com/docker/libcontainer/cgroups"
    11  	"github.com/docker/libnetwork/sandbox"
    12  )
    13  
    14  func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) error {
    15  	updates, err := daemon.SubscribeToContainerStats(name)
    16  	if err != nil {
    17  		return err
    18  	}
    19  
    20  	var preCpuStats types.CpuStats
    21  	getStat := func(v interface{}) *types.Stats {
    22  		update := v.(*execdriver.ResourceStats)
    23  		// Retrieve the nw statistics from libnetwork and inject them in the Stats
    24  		if nwStats, err := daemon.getNetworkStats(name); err == nil {
    25  			update.Stats.Interfaces = nwStats
    26  		}
    27  		ss := convertToAPITypes(update.Stats)
    28  		ss.PreCpuStats = preCpuStats
    29  		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
    30  		ss.Read = update.Read
    31  		ss.CpuStats.SystemUsage = update.SystemUsage
    32  		preCpuStats = ss.CpuStats
    33  		return ss
    34  	}
    35  
    36  	enc := json.NewEncoder(out)
    37  
    38  	if !stream {
    39  		// prime the cpu stats so they aren't 0 in the final output
    40  		s := getStat(<-updates)
    41  
    42  		// now pull stats again with the cpu stats primed
    43  		s = getStat(<-updates)
    44  		err := enc.Encode(s)
    45  		daemon.UnsubscribeToContainerStats(name, updates)
    46  		return err
    47  	}
    48  
    49  	for v := range updates {
    50  		s := getStat(v)
    51  		if err := enc.Encode(s); err != nil {
    52  			// TODO: handle the specific broken pipe
    53  			daemon.UnsubscribeToContainerStats(name, updates)
    54  			return err
    55  		}
    56  	}
    57  	return nil
    58  }
    59  
    60  // convertToAPITypes converts the libcontainer.Stats to the api specific
    61  // structs.  This is done to preserve API compatibility and versioning.
    62  func convertToAPITypes(ls *libcontainer.Stats) *types.Stats {
    63  	s := &types.Stats{}
    64  	if ls.Interfaces != nil {
    65  		s.Network = types.Network{}
    66  		for _, iface := range ls.Interfaces {
    67  			s.Network.RxBytes += iface.RxBytes
    68  			s.Network.RxPackets += iface.RxPackets
    69  			s.Network.RxErrors += iface.RxErrors
    70  			s.Network.RxDropped += iface.RxDropped
    71  			s.Network.TxBytes += iface.TxBytes
    72  			s.Network.TxPackets += iface.TxPackets
    73  			s.Network.TxErrors += iface.TxErrors
    74  			s.Network.TxDropped += iface.TxDropped
    75  		}
    76  	}
    77  	cs := ls.CgroupStats
    78  	if cs != nil {
    79  		s.BlkioStats = types.BlkioStats{
    80  			IoServiceBytesRecursive: copyBlkioEntry(cs.BlkioStats.IoServiceBytesRecursive),
    81  			IoServicedRecursive:     copyBlkioEntry(cs.BlkioStats.IoServicedRecursive),
    82  			IoQueuedRecursive:       copyBlkioEntry(cs.BlkioStats.IoQueuedRecursive),
    83  			IoServiceTimeRecursive:  copyBlkioEntry(cs.BlkioStats.IoServiceTimeRecursive),
    84  			IoWaitTimeRecursive:     copyBlkioEntry(cs.BlkioStats.IoWaitTimeRecursive),
    85  			IoMergedRecursive:       copyBlkioEntry(cs.BlkioStats.IoMergedRecursive),
    86  			IoTimeRecursive:         copyBlkioEntry(cs.BlkioStats.IoTimeRecursive),
    87  			SectorsRecursive:        copyBlkioEntry(cs.BlkioStats.SectorsRecursive),
    88  		}
    89  		cpu := cs.CpuStats
    90  		s.CpuStats = types.CpuStats{
    91  			CpuUsage: types.CpuUsage{
    92  				TotalUsage:        cpu.CpuUsage.TotalUsage,
    93  				PercpuUsage:       cpu.CpuUsage.PercpuUsage,
    94  				UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
    95  				UsageInUsermode:   cpu.CpuUsage.UsageInUsermode,
    96  			},
    97  			ThrottlingData: types.ThrottlingData{
    98  				Periods:          cpu.ThrottlingData.Periods,
    99  				ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
   100  				ThrottledTime:    cpu.ThrottlingData.ThrottledTime,
   101  			},
   102  		}
   103  		mem := cs.MemoryStats
   104  		s.MemoryStats = types.MemoryStats{
   105  			Usage:    mem.Usage,
   106  			MaxUsage: mem.MaxUsage,
   107  			Stats:    mem.Stats,
   108  			Failcnt:  mem.Failcnt,
   109  		}
   110  	}
   111  	return s
   112  }
   113  
   114  func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []types.BlkioStatEntry {
   115  	out := make([]types.BlkioStatEntry, len(entries))
   116  	for i, re := range entries {
   117  		out[i] = types.BlkioStatEntry{
   118  			Major: re.Major,
   119  			Minor: re.Minor,
   120  			Op:    re.Op,
   121  			Value: re.Value,
   122  		}
   123  	}
   124  	return out
   125  }
   126  
   127  func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInterface, error) {
   128  	var list []*libcontainer.NetworkInterface
   129  
   130  	c, err := daemon.Get(name)
   131  	if err != nil {
   132  		return list, err
   133  	}
   134  
   135  	nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
   136  	if err != nil {
   137  		return list, err
   138  	}
   139  	ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID)
   140  	if err != nil {
   141  		return list, err
   142  	}
   143  
   144  	stats, err := ep.Statistics()
   145  	if err != nil {
   146  		return list, err
   147  	}
   148  
   149  	// Convert libnetwork nw stats into libcontainer nw stats
   150  	for ifName, ifStats := range stats {
   151  		list = append(list, convertLnNetworkStats(ifName, ifStats))
   152  	}
   153  
   154  	return list, nil
   155  }
   156  
   157  func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface {
   158  	n := &libcontainer.NetworkInterface{Name: name}
   159  	n.RxBytes = stats.RxBytes
   160  	n.RxPackets = stats.RxPackets
   161  	n.RxErrors = stats.RxErrors
   162  	n.RxDropped = stats.RxDropped
   163  	n.TxBytes = stats.TxBytes
   164  	n.TxPackets = stats.TxPackets
   165  	n.TxErrors = stats.TxErrors
   166  	n.TxDropped = stats.TxDropped
   167  	return n
   168  }