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