github.com/baris/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 }