github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/daemon/metrics.go (about) 1 package daemon 2 3 import ( 4 "path/filepath" 5 "sync" 6 7 "github.com/docker/docker/pkg/mount" 8 "github.com/docker/docker/pkg/plugingetter" 9 metrics "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 imageActions metrics.LabeledTimer 20 networkActions metrics.LabeledTimer 21 engineInfo metrics.LabeledGauge 22 engineCpus metrics.Gauge 23 engineMemory metrics.Gauge 24 healthChecksCounter metrics.Counter 25 healthChecksFailedCounter metrics.Counter 26 27 stateCtr *stateCounter 28 ) 29 30 func init() { 31 ns := metrics.NewNamespace("engine", "daemon", nil) 32 containerActions = ns.NewLabeledTimer("container_actions", "The number of seconds it takes to process each container action", "action") 33 for _, a := range []string{ 34 "start", 35 "changes", 36 "commit", 37 "create", 38 "delete", 39 } { 40 containerActions.WithValues(a).Update(0) 41 } 42 43 networkActions = ns.NewLabeledTimer("network_actions", "The number of seconds it takes to process each network action", "action") 44 engineInfo = ns.NewLabeledGauge("engine", "The information related to the engine and the OS it is running on", metrics.Unit("info"), 45 "version", 46 "commit", 47 "architecture", 48 "graphdriver", 49 "kernel", "os", 50 "os_type", 51 "daemon_id", // ID is a randomly generated unique identifier (e.g. UUID4) 52 ) 53 engineCpus = ns.NewGauge("engine_cpus", "The number of cpus that the host system of the engine has", metrics.Unit("cpus")) 54 engineMemory = ns.NewGauge("engine_memory", "The number of bytes of memory that the host system of the engine has", metrics.Bytes) 55 healthChecksCounter = ns.NewCounter("health_checks", "The total number of health checks") 56 healthChecksFailedCounter = ns.NewCounter("health_checks_failed", "The total number of failed health checks") 57 imageActions = ns.NewLabeledTimer("image_actions", "The number of seconds it takes to process each image action", "action") 58 59 stateCtr = newStateCounter(ns.NewDesc("container_states", "The count of containers in various states", metrics.Unit("containers"), "state")) 60 ns.Add(stateCtr) 61 62 metrics.Register(ns) 63 } 64 65 type stateCounter struct { 66 mu sync.Mutex 67 states map[string]string 68 desc *prometheus.Desc 69 } 70 71 func newStateCounter(desc *prometheus.Desc) *stateCounter { 72 return &stateCounter{ 73 states: make(map[string]string), 74 desc: desc, 75 } 76 } 77 78 func (ctr *stateCounter) get() (running int, paused int, stopped int) { 79 ctr.mu.Lock() 80 defer ctr.mu.Unlock() 81 82 states := map[string]int{ 83 "running": 0, 84 "paused": 0, 85 "stopped": 0, 86 } 87 for _, state := range ctr.states { 88 states[state]++ 89 } 90 return states["running"], states["paused"], states["stopped"] 91 } 92 93 func (ctr *stateCounter) set(id, label string) { 94 ctr.mu.Lock() 95 ctr.states[id] = label 96 ctr.mu.Unlock() 97 } 98 99 func (ctr *stateCounter) del(id string) { 100 ctr.mu.Lock() 101 delete(ctr.states, id) 102 ctr.mu.Unlock() 103 } 104 105 func (ctr *stateCounter) Describe(ch chan<- *prometheus.Desc) { 106 ch <- ctr.desc 107 } 108 109 func (ctr *stateCounter) Collect(ch chan<- prometheus.Metric) { 110 running, paused, stopped := ctr.get() 111 ch <- prometheus.MustNewConstMetric(ctr.desc, prometheus.GaugeValue, float64(running), "running") 112 ch <- prometheus.MustNewConstMetric(ctr.desc, prometheus.GaugeValue, float64(paused), "paused") 113 ch <- prometheus.MustNewConstMetric(ctr.desc, prometheus.GaugeValue, float64(stopped), "stopped") 114 } 115 116 func (d *Daemon) cleanupMetricsPlugins() { 117 ls := d.PluginStore.GetAllManagedPluginsByCap(metricsPluginType) 118 var wg sync.WaitGroup 119 wg.Add(len(ls)) 120 121 for _, p := range ls { 122 go func() { 123 defer wg.Done() 124 pluginStopMetricsCollection(p) 125 }() 126 } 127 wg.Wait() 128 129 if d.metricsPluginListener != nil { 130 d.metricsPluginListener.Close() 131 } 132 } 133 134 type metricsPlugin struct { 135 plugingetter.CompatPlugin 136 } 137 138 func (p metricsPlugin) sock() string { 139 return "metrics.sock" 140 } 141 142 func (p metricsPlugin) sockBase() string { 143 return filepath.Join(p.BasePath(), "run", "docker") 144 } 145 146 func pluginStartMetricsCollection(p plugingetter.CompatPlugin) error { 147 type metricsPluginResponse struct { 148 Err string 149 } 150 var res metricsPluginResponse 151 if err := p.Client().Call(metricsPluginType+".StartMetrics", nil, &res); err != nil { 152 return errors.Wrap(err, "could not start metrics plugin") 153 } 154 if res.Err != "" { 155 return errors.New(res.Err) 156 } 157 return nil 158 } 159 160 func pluginStopMetricsCollection(p plugingetter.CompatPlugin) { 161 if err := p.Client().Call(metricsPluginType+".StopMetrics", nil, nil); err != nil { 162 logrus.WithError(err).WithField("name", p.Name()).Error("error stopping metrics collector") 163 } 164 165 mp := metricsPlugin{p} 166 sockPath := filepath.Join(mp.sockBase(), mp.sock()) 167 if err := mount.Unmount(sockPath); err != nil { 168 if mounted, _ := mount.Mounted(sockPath); mounted { 169 logrus.WithError(err).WithField("name", p.Name()).WithField("socket", sockPath).Error("error unmounting metrics socket for plugin") 170 } 171 } 172 }