github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/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 _, plugin := range ls {
   122  		p := plugin
   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  }