github.com/mforkel/docker-ce-i386@v17.12.1-ce-rc2+incompatible/components/engine/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  }