github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/daemon/metrics.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "sync" 5 6 "github.com/docker/docker/errdefs" 7 "github.com/docker/docker/pkg/plugingetter" 8 "github.com/docker/docker/pkg/plugins" 9 "github.com/docker/go-metrics" 10 "github.com/pkg/errors" 11 "github.com/prometheus/client_golang/prometheus" 12 "github.com/sirupsen/logrus" 13 ) 14 15 const metricsPluginType = "MetricsCollector" 16 17 var ( 18 containerActions metrics.LabeledTimer 19 networkActions metrics.LabeledTimer 20 engineInfo metrics.LabeledGauge 21 engineCpus metrics.Gauge 22 engineMemory metrics.Gauge 23 healthChecksCounter metrics.Counter 24 healthChecksFailedCounter metrics.Counter 25 26 stateCtr *stateCounter 27 ) 28 29 func init() { 30 ns := metrics.NewNamespace("engine", "daemon", nil) 31 containerActions = ns.NewLabeledTimer("container_actions", "The number of seconds it takes to process each container action", "action") 32 for _, a := range []string{ 33 "start", 34 "changes", 35 "commit", 36 "create", 37 "delete", 38 } { 39 containerActions.WithValues(a).Update(0) 40 } 41 42 networkActions = ns.NewLabeledTimer("network_actions", "The number of seconds it takes to process each network action", "action") 43 engineInfo = ns.NewLabeledGauge("engine", "The information related to the engine and the OS it is running on", metrics.Unit("info"), 44 "version", 45 "commit", 46 "architecture", 47 "graphdriver", 48 "kernel", "os", 49 "os_type", 50 "daemon_id", // ID is a randomly generated unique identifier (e.g. UUID4) 51 ) 52 engineCpus = ns.NewGauge("engine_cpus", "The number of cpus that the host system of the engine has", metrics.Unit("cpus")) 53 engineMemory = ns.NewGauge("engine_memory", "The number of bytes of memory that the host system of the engine has", metrics.Bytes) 54 healthChecksCounter = ns.NewCounter("health_checks", "The total number of health checks") 55 healthChecksFailedCounter = ns.NewCounter("health_checks_failed", "The total number of failed health checks") 56 57 stateCtr = newStateCounter(ns.NewDesc("container_states", "The count of containers in various states", metrics.Unit("containers"), "state")) 58 ns.Add(stateCtr) 59 60 metrics.Register(ns) 61 } 62 63 type stateCounter struct { 64 mu sync.Mutex 65 states map[string]string 66 desc *prometheus.Desc 67 } 68 69 func newStateCounter(desc *prometheus.Desc) *stateCounter { 70 return &stateCounter{ 71 states: make(map[string]string), 72 desc: desc, 73 } 74 } 75 76 func (ctr *stateCounter) get() (running int, paused int, stopped int) { 77 ctr.mu.Lock() 78 defer ctr.mu.Unlock() 79 80 states := map[string]int{ 81 "running": 0, 82 "paused": 0, 83 "stopped": 0, 84 } 85 for _, state := range ctr.states { 86 states[state]++ 87 } 88 return states["running"], states["paused"], states["stopped"] 89 } 90 91 func (ctr *stateCounter) set(id, label string) { 92 ctr.mu.Lock() 93 ctr.states[id] = label 94 ctr.mu.Unlock() 95 } 96 97 func (ctr *stateCounter) del(id string) { 98 ctr.mu.Lock() 99 delete(ctr.states, id) 100 ctr.mu.Unlock() 101 } 102 103 func (ctr *stateCounter) Describe(ch chan<- *prometheus.Desc) { 104 ch <- ctr.desc 105 } 106 107 func (ctr *stateCounter) Collect(ch chan<- prometheus.Metric) { 108 running, paused, stopped := ctr.get() 109 ch <- prometheus.MustNewConstMetric(ctr.desc, prometheus.GaugeValue, float64(running), "running") 110 ch <- prometheus.MustNewConstMetric(ctr.desc, prometheus.GaugeValue, float64(paused), "paused") 111 ch <- prometheus.MustNewConstMetric(ctr.desc, prometheus.GaugeValue, float64(stopped), "stopped") 112 } 113 114 func (d *Daemon) cleanupMetricsPlugins() { 115 ls := d.PluginStore.GetAllManagedPluginsByCap(metricsPluginType) 116 var wg sync.WaitGroup 117 wg.Add(len(ls)) 118 119 for _, plugin := range ls { 120 p := plugin 121 go func() { 122 defer wg.Done() 123 124 adapter, err := makePluginAdapter(p) 125 if err != nil { 126 logrus.WithError(err).WithField("plugin", p.Name()).Error("Error creating metrics plugin adapater") 127 return 128 } 129 if err := adapter.StopMetrics(); err != nil { 130 logrus.WithError(err).WithField("plugin", p.Name()).Error("Error stopping plugin metrics collection") 131 } 132 }() 133 } 134 wg.Wait() 135 136 if d.metricsPluginListener != nil { 137 d.metricsPluginListener.Close() 138 } 139 } 140 141 type metricsPlugin interface { 142 StartMetrics() error 143 StopMetrics() error 144 } 145 146 func makePluginAdapter(p plugingetter.CompatPlugin) (metricsPlugin, error) { // nolint: interfacer 147 if pc, ok := p.(plugingetter.PluginWithV1Client); ok { 148 return &metricsPluginAdapter{pc.Client(), p.Name()}, nil 149 } 150 151 pa, ok := p.(plugingetter.PluginAddr) 152 if !ok { 153 return nil, errdefs.System(errors.Errorf("got unknown plugin type %T", p)) 154 } 155 156 if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 { 157 return nil, errors.Errorf("plugin protocol not supported: %s", pa.Protocol()) 158 } 159 160 addr := pa.Addr() 161 client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout()) 162 if err != nil { 163 return nil, errors.Wrap(err, "error creating metrics plugin client") 164 } 165 return &metricsPluginAdapter{client, p.Name()}, nil 166 } 167 168 type metricsPluginAdapter struct { 169 c *plugins.Client 170 name string 171 } 172 173 func (a *metricsPluginAdapter) StartMetrics() error { 174 type metricsPluginResponse struct { 175 Err string 176 } 177 var res metricsPluginResponse 178 if err := a.c.Call(metricsPluginType+".StartMetrics", nil, &res); err != nil { 179 return errors.Wrap(err, "could not start metrics plugin") 180 } 181 if res.Err != "" { 182 return errors.New(res.Err) 183 } 184 return nil 185 } 186 187 func (a *metricsPluginAdapter) StopMetrics() error { 188 if err := a.c.Call(metricsPluginType+".StopMetrics", nil, nil); err != nil { 189 return errors.Wrap(err, "error stopping metrics collector") 190 } 191 return nil 192 }