github.com/circular-dark/docker@v1.7.0/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  )
    12  
    13  func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) error {
    14  	updates, err := daemon.SubscribeToContainerStats(name)
    15  	if err != nil {
    16  		return err
    17  	}
    18  
    19  	var preCpuStats types.CpuStats
    20  	getStat := func(v interface{}) *types.Stats {
    21  		update := v.(*execdriver.ResourceStats)
    22  		ss := convertToAPITypes(update.Stats)
    23  		ss.PreCpuStats = preCpuStats
    24  		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
    25  		ss.Read = update.Read
    26  		ss.CpuStats.SystemUsage = update.SystemUsage
    27  		preCpuStats = ss.CpuStats
    28  		return ss
    29  	}
    30  
    31  	enc := json.NewEncoder(out)
    32  
    33  	if !stream {
    34  		// prime the cpu stats so they aren't 0 in the final output
    35  		s := getStat(<-updates)
    36  
    37  		// now pull stats again with the cpu stats primed
    38  		s = getStat(<-updates)
    39  		err := enc.Encode(s)
    40  		daemon.UnsubscribeToContainerStats(name, updates)
    41  		return err
    42  	}
    43  
    44  	for v := range updates {
    45  		s := getStat(v)
    46  		if err := enc.Encode(s); err != nil {
    47  			// TODO: handle the specific broken pipe
    48  			daemon.UnsubscribeToContainerStats(name, updates)
    49  			return err
    50  		}
    51  	}
    52  	return nil
    53  }
    54  
    55  // convertToAPITypes converts the libcontainer.Stats to the api specific
    56  // structs.  This is done to preserve API compatibility and versioning.
    57  func convertToAPITypes(ls *libcontainer.Stats) *types.Stats {
    58  	s := &types.Stats{}
    59  	if ls.Interfaces != nil {
    60  		s.Network = types.Network{}
    61  		for _, iface := range ls.Interfaces {
    62  			s.Network.RxBytes += iface.RxBytes
    63  			s.Network.RxPackets += iface.RxPackets
    64  			s.Network.RxErrors += iface.RxErrors
    65  			s.Network.RxDropped += iface.RxDropped
    66  			s.Network.TxBytes += iface.TxBytes
    67  			s.Network.TxPackets += iface.TxPackets
    68  			s.Network.TxErrors += iface.TxErrors
    69  			s.Network.TxDropped += iface.TxDropped
    70  		}
    71  	}
    72  	cs := ls.CgroupStats
    73  	if cs != nil {
    74  		s.BlkioStats = types.BlkioStats{
    75  			IoServiceBytesRecursive: copyBlkioEntry(cs.BlkioStats.IoServiceBytesRecursive),
    76  			IoServicedRecursive:     copyBlkioEntry(cs.BlkioStats.IoServicedRecursive),
    77  			IoQueuedRecursive:       copyBlkioEntry(cs.BlkioStats.IoQueuedRecursive),
    78  			IoServiceTimeRecursive:  copyBlkioEntry(cs.BlkioStats.IoServiceTimeRecursive),
    79  			IoWaitTimeRecursive:     copyBlkioEntry(cs.BlkioStats.IoWaitTimeRecursive),
    80  			IoMergedRecursive:       copyBlkioEntry(cs.BlkioStats.IoMergedRecursive),
    81  			IoTimeRecursive:         copyBlkioEntry(cs.BlkioStats.IoTimeRecursive),
    82  			SectorsRecursive:        copyBlkioEntry(cs.BlkioStats.SectorsRecursive),
    83  		}
    84  		cpu := cs.CpuStats
    85  		s.CpuStats = types.CpuStats{
    86  			CpuUsage: types.CpuUsage{
    87  				TotalUsage:        cpu.CpuUsage.TotalUsage,
    88  				PercpuUsage:       cpu.CpuUsage.PercpuUsage,
    89  				UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
    90  				UsageInUsermode:   cpu.CpuUsage.UsageInUsermode,
    91  			},
    92  			ThrottlingData: types.ThrottlingData{
    93  				Periods:          cpu.ThrottlingData.Periods,
    94  				ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
    95  				ThrottledTime:    cpu.ThrottlingData.ThrottledTime,
    96  			},
    97  		}
    98  		mem := cs.MemoryStats
    99  		s.MemoryStats = types.MemoryStats{
   100  			Usage:    mem.Usage,
   101  			MaxUsage: mem.MaxUsage,
   102  			Stats:    mem.Stats,
   103  			Failcnt:  mem.Failcnt,
   104  		}
   105  	}
   106  	return s
   107  }
   108  
   109  func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []types.BlkioStatEntry {
   110  	out := make([]types.BlkioStatEntry, len(entries))
   111  	for i, re := range entries {
   112  		out[i] = types.BlkioStatEntry{
   113  			Major: re.Major,
   114  			Minor: re.Minor,
   115  			Op:    re.Op,
   116  			Value: re.Value,
   117  		}
   118  	}
   119  	return out
   120  }