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  }