github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/metrics/spool/manifold.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package spool contains the implementation of a 5 // worker that extracts the spool directory path from the agent 6 // config and enables other workers to write and read 7 // metrics to and from a the spool directory using a writer 8 // and a reader. 9 package spool 10 11 import ( 12 "time" 13 14 "github.com/juju/errors" 15 corecharm "gopkg.in/juju/charm.v6" 16 "gopkg.in/juju/worker.v1" 17 "gopkg.in/juju/worker.v1/dependency" 18 "gopkg.in/tomb.v2" 19 20 "github.com/juju/juju/agent" 21 "github.com/juju/juju/cmd/jujud/agent/engine" 22 ) 23 24 // MetricRecorder records metrics to a spool directory. 25 type MetricRecorder interface { 26 // AddMetric records a metric with the specified key, value, create time 27 // and labels to a spool directory. 28 AddMetric(key, value string, created time.Time, labels map[string]string) error 29 // Close implements io.Closer. 30 Close() error 31 // IsDeclaredMetrics returns true if the metric recorder 32 // is permitted to store metrics with the specified key. 33 IsDeclaredMetric(key string) bool 34 } 35 36 // MetricReader reads metrics from a spool directory. 37 type MetricReader interface { 38 // Read returns all metric batches stored in the spool directory. 39 Read() ([]MetricBatch, error) 40 // Remove removes the metric batch with the specified uuid 41 // from the spool directory. 42 Remove(uuid string) error 43 // Close implements io.Closer. 44 Close() error 45 } 46 47 // MetricFactory contains the metrics reader and recorder factories. 48 type MetricFactory interface { 49 // Recorder returns a new MetricRecorder. 50 Recorder(metrics map[string]corecharm.Metric, charmURL, unitTag string) (MetricRecorder, error) 51 52 // Reader returns a new MetricReader. 53 Reader() (MetricReader, error) 54 } 55 56 type factory struct { 57 spoolDir string 58 } 59 60 // Reader implements the MetricFactory interface. 61 func (f *factory) Reader() (MetricReader, error) { 62 return NewJSONMetricReader(f.spoolDir) 63 } 64 65 // Recorder implements the MetricFactory interface. 66 func (f *factory) Recorder(declaredMetrics map[string]corecharm.Metric, charmURL, unitTag string) (MetricRecorder, error) { 67 return NewJSONMetricRecorder(MetricRecorderConfig{ 68 SpoolDir: f.spoolDir, 69 Metrics: declaredMetrics, 70 CharmURL: charmURL, 71 UnitTag: unitTag, 72 }) 73 } 74 75 var newFactory = func(spoolDir string) MetricFactory { 76 return &factory{spoolDir: spoolDir} 77 } 78 79 // ManifoldConfig specifies names a spooldirectory manifold should use to 80 // address its dependencies. 81 type ManifoldConfig engine.AgentManifoldConfig 82 83 // Manifold returns a dependency.Manifold that extracts the metrics 84 // spool directory path from the agent. 85 func Manifold(config ManifoldConfig) dependency.Manifold { 86 manifold := engine.AgentManifold(engine.AgentManifoldConfig(config), newWorker) 87 manifold.Output = outputFunc 88 return manifold 89 } 90 91 // newWorker creates a degenerate worker that provides access to the metrics 92 // spool directory path. 93 func newWorker(a agent.Agent) (worker.Worker, error) { 94 metricsSpoolDir := a.CurrentConfig().MetricsSpoolDir() 95 err := checkSpoolDir(metricsSpoolDir) 96 if err != nil { 97 return nil, errors.Annotatef(err, "error checking spool directory %q", metricsSpoolDir) 98 } 99 w := &spoolWorker{factory: newFactory(metricsSpoolDir)} 100 w.tomb.Go(func() error { 101 <-w.tomb.Dying() 102 return nil 103 }) 104 return w, nil 105 } 106 107 // outputFunc extracts the metrics spool directory path from a *metricsSpoolDirWorker. 108 func outputFunc(in worker.Worker, out interface{}) error { 109 inWorker, _ := in.(*spoolWorker) 110 outPointer, _ := out.(*MetricFactory) 111 if inWorker == nil || outPointer == nil { 112 return errors.Errorf("expected %T->%T; got %T->%T", inWorker, outPointer, in, out) 113 } 114 *outPointer = inWorker.factory 115 return nil 116 } 117 118 // spoolWorker is a worker that provides a MetricFactory. 119 type spoolWorker struct { 120 tomb tomb.Tomb 121 factory MetricFactory 122 } 123 124 // Kill is part of the worker.Worker interface. 125 func (w *spoolWorker) Kill() { 126 w.tomb.Kill(nil) 127 } 128 129 // Wait is part of the worker.Worker interface. 130 func (w *spoolWorker) Wait() error { 131 return w.tomb.Wait() 132 }