github.com/akashshinde/docker@v1.9.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/api/types/versions/v1p20" 9 "github.com/docker/docker/daemon/execdriver" 10 "github.com/docker/docker/pkg/version" 11 ) 12 13 // ContainerStatsConfig holds information for configuring the runtime 14 // behavior of a daemon.ContainerStats() call. 15 type ContainerStatsConfig struct { 16 Stream bool 17 OutStream io.Writer 18 Stop <-chan bool 19 Version version.Version 20 } 21 22 // ContainerStats writes information about the container to the stream 23 // given in the config object. 24 func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStatsConfig) error { 25 26 container, err := daemon.Get(prefixOrName) 27 if err != nil { 28 return err 29 } 30 31 // If the container is not running and requires no stream, return an empty stats. 32 if !container.IsRunning() && !config.Stream { 33 return json.NewEncoder(config.OutStream).Encode(&types.Stats{}) 34 } 35 36 updates, err := daemon.subscribeToContainerStats(container) 37 if err != nil { 38 return err 39 } 40 41 if config.Stream { 42 // Write an empty chunk of data. 43 // This is to ensure that the HTTP status code is sent immediately, 44 // even if the container has not yet produced any data. 45 config.OutStream.Write(nil) 46 } 47 48 var preCPUStats types.CPUStats 49 getStatJSON := func(v interface{}) *types.StatsJSON { 50 update := v.(*execdriver.ResourceStats) 51 ss := convertStatsToAPITypes(update.Stats) 52 ss.PreCPUStats = preCPUStats 53 ss.MemoryStats.Limit = uint64(update.MemoryLimit) 54 ss.Read = update.Read 55 ss.CPUStats.SystemUsage = update.SystemUsage 56 preCPUStats = ss.CPUStats 57 return ss 58 } 59 60 enc := json.NewEncoder(config.OutStream) 61 62 defer daemon.unsubscribeToContainerStats(container, updates) 63 64 noStreamFirstFrame := true 65 for { 66 select { 67 case v, ok := <-updates: 68 if !ok { 69 return nil 70 } 71 72 var statsJSON interface{} 73 statsJSONPost120 := getStatJSON(v) 74 if config.Version.LessThan("1.21") { 75 var ( 76 rxBytes uint64 77 rxPackets uint64 78 rxErrors uint64 79 rxDropped uint64 80 txBytes uint64 81 txPackets uint64 82 txErrors uint64 83 txDropped uint64 84 ) 85 for _, v := range statsJSONPost120.Networks { 86 rxBytes += v.RxBytes 87 rxPackets += v.RxPackets 88 rxErrors += v.RxErrors 89 rxDropped += v.RxDropped 90 txBytes += v.TxBytes 91 txPackets += v.TxPackets 92 txErrors += v.TxErrors 93 txDropped += v.TxDropped 94 } 95 statsJSON = &v1p20.StatsJSON{ 96 Stats: statsJSONPost120.Stats, 97 Network: types.NetworkStats{ 98 RxBytes: rxBytes, 99 RxPackets: rxPackets, 100 RxErrors: rxErrors, 101 RxDropped: rxDropped, 102 TxBytes: txBytes, 103 TxPackets: txPackets, 104 TxErrors: txErrors, 105 TxDropped: txDropped, 106 }, 107 } 108 } else { 109 statsJSON = statsJSONPost120 110 } 111 112 if !config.Stream && noStreamFirstFrame { 113 // prime the cpu stats so they aren't 0 in the final output 114 noStreamFirstFrame = false 115 continue 116 } 117 118 if err := enc.Encode(statsJSON); err != nil { 119 return err 120 } 121 122 if !config.Stream { 123 return nil 124 } 125 case <-config.Stop: 126 return nil 127 } 128 } 129 }