github.com/torfuzx/docker@v1.8.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/libnetwork/sandbox" 10 "github.com/opencontainers/runc/libcontainer" 11 ) 12 13 type ContainerStatsConfig struct { 14 Stream bool 15 OutStream io.Writer 16 Stop <-chan bool 17 } 18 19 func (daemon *Daemon) ContainerStats(name string, config *ContainerStatsConfig) error { 20 updates, err := daemon.SubscribeToContainerStats(name) 21 if err != nil { 22 return err 23 } 24 25 if config.Stream { 26 config.OutStream.Write(nil) 27 } 28 29 var preCpuStats types.CpuStats 30 getStat := func(v interface{}) *types.Stats { 31 update := v.(*execdriver.ResourceStats) 32 // Retrieve the nw statistics from libnetwork and inject them in the Stats 33 if nwStats, err := daemon.getNetworkStats(name); err == nil { 34 update.Stats.Interfaces = nwStats 35 } 36 ss := convertStatsToAPITypes(update.Stats) 37 ss.PreCpuStats = preCpuStats 38 ss.MemoryStats.Limit = uint64(update.MemoryLimit) 39 ss.Read = update.Read 40 ss.CpuStats.SystemUsage = update.SystemUsage 41 preCpuStats = ss.CpuStats 42 return ss 43 } 44 45 enc := json.NewEncoder(config.OutStream) 46 47 defer daemon.UnsubscribeToContainerStats(name, updates) 48 49 noStreamFirstFrame := true 50 for { 51 select { 52 case v, ok := <-updates: 53 if !ok { 54 return nil 55 } 56 57 s := getStat(v) 58 if !config.Stream && noStreamFirstFrame { 59 // prime the cpu stats so they aren't 0 in the final output 60 noStreamFirstFrame = false 61 continue 62 } 63 64 if err := enc.Encode(s); err != nil { 65 return err 66 } 67 68 if !config.Stream { 69 return nil 70 } 71 case <-config.Stop: 72 return nil 73 } 74 } 75 } 76 77 func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInterface, error) { 78 var list []*libcontainer.NetworkInterface 79 80 c, err := daemon.Get(name) 81 if err != nil { 82 return list, err 83 } 84 85 nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID) 86 if err != nil { 87 return list, err 88 } 89 ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID) 90 if err != nil { 91 return list, err 92 } 93 94 stats, err := ep.Statistics() 95 if err != nil { 96 return list, err 97 } 98 99 // Convert libnetwork nw stats into libcontainer nw stats 100 for ifName, ifStats := range stats { 101 list = append(list, convertLnNetworkStats(ifName, ifStats)) 102 } 103 104 return list, nil 105 } 106 107 func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface { 108 n := &libcontainer.NetworkInterface{Name: name} 109 n.RxBytes = stats.RxBytes 110 n.RxPackets = stats.RxPackets 111 n.RxErrors = stats.RxErrors 112 n.RxDropped = stats.RxDropped 113 n.TxBytes = stats.TxBytes 114 n.TxPackets = stats.TxPackets 115 n.TxErrors = stats.TxErrors 116 n.TxDropped = stats.TxDropped 117 return n 118 }