github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/observer/metricobserver/metricobserver.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package metricobserver 5 6 import ( 7 "net/http" 8 "strconv" 9 "time" 10 11 "github.com/juju/clock" 12 "github.com/juju/errors" 13 "github.com/prometheus/client_golang/prometheus" 14 "gopkg.in/juju/names.v2" 15 16 "github.com/juju/juju/apiserver/observer" 17 "github.com/juju/juju/rpc" 18 ) 19 20 // MetricLabels used for setting labels for the Counter and Summary vectors. 21 const ( 22 MetricLabelFacade = "facade" 23 MetricLabelVersion = "version" 24 MetricLabelMethod = "method" 25 MetricLabelErrorCode = "error_code" 26 ) 27 28 // MetricLabelNames holds the names for reporting the names of the metric 29 // types when calling the observers. 30 var MetricLabelNames = []string{ 31 MetricLabelFacade, 32 MetricLabelVersion, 33 MetricLabelMethod, 34 MetricLabelErrorCode, 35 } 36 37 // CounterVec is a Collector that bundles a set of Counters that all share the 38 // same description. 39 type CounterVec interface { 40 // With returns a Counter for a given labels slice 41 With(prometheus.Labels) prometheus.Counter 42 } 43 44 // SummaryVec is a Collector that bundles a set of Summaries that all share the 45 // same description. 46 type SummaryVec interface { 47 // With returns a Summary for a given labels slice 48 With(prometheus.Labels) prometheus.Observer 49 } 50 51 // MetricsCollector represents a bundle of metrics that is used by the observer 52 // factory. 53 //go:generate mockgen -package mocks -destination mocks/metrics_collector_mock.go github.com/juju/juju/apiserver/observer/metricobserver MetricsCollector,CounterVec,SummaryVec 54 //go:generate mockgen -package mocks -destination mocks/metrics_mock.go github.com/prometheus/client_golang/prometheus Counter,Summary 55 type MetricsCollector interface { 56 // APIRequestDuration returns a SummaryVec for updating the duration of 57 // api request duration. 58 APIRequestDuration() SummaryVec 59 60 // DeprecatedAPIRequestsTotal returns a CounterVec for updating the number of 61 // api requests total. 62 // The following is obsolete and should be removed for 2.6 release 63 DeprecatedAPIRequestsTotal() CounterVec 64 65 // DeprecatedAPIRequestDuration returns a SummaryVec for updating the duration of 66 // api request duration. 67 // The following is obsolete and should be removed for 2.6 release 68 DeprecatedAPIRequestDuration() SummaryVec 69 } 70 71 // Config contains the configuration for an Observer. 72 type Config struct { 73 // Clock is the clock to use for all time-related operations. 74 Clock clock.Clock 75 76 // MetricsCollector defines . 77 MetricsCollector MetricsCollector 78 } 79 80 // Validate validates the observer factory configuration. 81 func (cfg Config) Validate() error { 82 if cfg.Clock == nil { 83 return errors.NotValidf("nil Clock") 84 } 85 if cfg.MetricsCollector == nil { 86 return errors.NotValidf("nil MetricsCollector") 87 } 88 return nil 89 } 90 91 // NewObserverFactory returns a function that, when called, returns a new 92 // Observer. NewObserverFactory registers the API request metrics, and 93 // each Observer updates those metrics. 94 func NewObserverFactory(config Config) (observer.ObserverFactory, error) { 95 if err := config.Validate(); err != nil { 96 return nil, errors.Annotate(err, "validating config") 97 } 98 99 // Observer is currently stateless, so we return the same one for each 100 // API connection. Individual RPC requests still get their own RPC 101 // observers. 102 o := &Observer{ 103 clock: config.Clock, 104 metrics: metrics{ 105 apiRequestDuration: config.MetricsCollector.APIRequestDuration(), 106 deprecatedAPIRequestsTotal: config.MetricsCollector.DeprecatedAPIRequestsTotal(), 107 deprecatedAPIRequestDuration: config.MetricsCollector.DeprecatedAPIRequestDuration(), 108 }, 109 } 110 return func() observer.Observer { 111 return o 112 }, nil 113 } 114 115 // Observer is an API server request observer that collects Prometheus metrics. 116 type Observer struct { 117 clock clock.Clock 118 metrics metrics 119 } 120 121 type metrics struct { 122 apiRequestDuration SummaryVec 123 deprecatedAPIRequestDuration SummaryVec 124 deprecatedAPIRequestsTotal CounterVec 125 } 126 127 // Login is part of the observer.Observer interface. 128 func (*Observer) Login(entity names.Tag, _ names.ModelTag, _ bool, _ string) {} 129 130 // Join is part of the observer.Observer interface. 131 func (*Observer) Join(req *http.Request, connectionID uint64) {} 132 133 // Leave is part of the observer.Observer interface. 134 func (*Observer) Leave() {} 135 136 // RPCObserver is part of the observer.Observer interface. 137 func (o *Observer) RPCObserver() rpc.Observer { 138 return &rpcObserver{ 139 clock: o.clock, 140 metrics: o.metrics, 141 } 142 } 143 144 type rpcObserver struct { 145 clock clock.Clock 146 metrics metrics 147 requestStart time.Time 148 } 149 150 // ServerRequest is part of the rpc.Observer interface. 151 func (o *rpcObserver) ServerRequest(hdr *rpc.Header, body interface{}) { 152 o.requestStart = o.clock.Now() 153 } 154 155 // ServerReply is part of the rpc.Observer interface. 156 func (o *rpcObserver) ServerReply(req rpc.Request, hdr *rpc.Header, body interface{}) { 157 labels := prometheus.Labels{ 158 MetricLabelFacade: req.Type, 159 MetricLabelVersion: strconv.Itoa(req.Version), 160 MetricLabelMethod: req.Action, 161 MetricLabelErrorCode: hdr.ErrorCode, 162 } 163 duration := o.clock.Now().Sub(o.requestStart) 164 o.metrics.apiRequestDuration.With(labels).Observe(duration.Seconds()) 165 166 // The following is obsolete and should be removed for 2.6 release 167 o.metrics.deprecatedAPIRequestDuration.With(labels).Observe(duration.Seconds()) 168 o.metrics.deprecatedAPIRequestsTotal.With(labels).Inc() 169 }