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