From f9ed0ccb829a9b2cc8d2d31bcf2ff850bee4d3a7 Mon Sep 17 00:00:00 2001 From: Johnny Steenbergen Date: Mon, 3 Feb 2020 09:39:01 -0800 Subject: [PATCH] feat(pkger): add metrics svc middleware --- cmd/influxd/launcher/launcher.go | 1 + kit/metric/client.go | 73 ++++++++++++++++++++++++++++++++ pkger/service_metrics.go | 46 ++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 kit/metric/client.go create mode 100644 pkger/service_metrics.go diff --git a/cmd/influxd/launcher/launcher.go b/cmd/influxd/launcher/launcher.go index 9586d0902a..6fc3035ee6 100644 --- a/cmd/influxd/launcher/launcher.go +++ b/cmd/influxd/launcher/launcher.go @@ -831,6 +831,7 @@ func (m *Launcher) run(ctx context.Context) (err error) { pkger.WithVariableSVC(authorizer.NewVariableService(b.VariableService)), ) pkgSVC = pkger.MWTracing()(pkgSVC) + pkgSVC = pkger.MWMetrics(m.reg)(pkgSVC) pkgSVC = pkger.MWLogging(pkgerLogger)(pkgSVC) } diff --git a/kit/metric/client.go b/kit/metric/client.go new file mode 100644 index 0000000000..42c472c077 --- /dev/null +++ b/kit/metric/client.go @@ -0,0 +1,73 @@ +package metric + +import ( + "fmt" + "time" + + "github.com/influxdata/influxdb" + "github.com/influxdata/influxdb/kit/prom" + "github.com/prometheus/client_golang/prometheus" +) + +// REDClient is a metrics client for collection RED metrics. +type REDClient struct { + // RED metrics + reqs *prometheus.CounterVec + errs *prometheus.CounterVec + durs *prometheus.HistogramVec +} + +// New creates a new REDClient. +func New(reg *prom.Registry, service string) *REDClient { + // MiddlewareMetrics is a metrics service middleware for the notification endpoint service. + const namespace = "service" + + reqs := prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: service, + Name: "call_total", + Help: fmt.Sprintf("Number of calls to the %s service", service), + }, []string{"method"}) + + errs := prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: service, + Name: "error_total", + Help: fmt.Sprintf("Number of errors encountered when calling the %s service", service), + }, []string{"method", "code"}) + + durs := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: service, + Name: "duration", + Help: fmt.Sprintf("Duration of %s service calls", service), + }, []string{"method"}) + + reg.MustRegister(reqs, errs, durs) + + return &REDClient{ + reqs: reqs, + errs: errs, + durs: durs, + } +} + +// Record returns a record fn that is called on any given return err. If an error is encountered +// it will register the err metric. The err is never altered. +func (c *REDClient) Record(method string) func(error) error { + start := time.Now() + return func(err error) error { + c.reqs.With(prometheus.Labels{"method": method}) + + if err != nil { + c.errs.With(prometheus.Labels{ + "method": method, + "code": influxdb.ErrorCode(err), + }).Inc() + } + + c.durs.With(prometheus.Labels{"method": method}).Observe(time.Since(start).Seconds()) + + return err + } +} diff --git a/pkger/service_metrics.go b/pkger/service_metrics.go new file mode 100644 index 0000000000..6d9276ecdc --- /dev/null +++ b/pkger/service_metrics.go @@ -0,0 +1,46 @@ +package pkger + +import ( + "context" + + "github.com/influxdata/influxdb" + "github.com/influxdata/influxdb/kit/metric" + "github.com/influxdata/influxdb/kit/prom" +) + +type mwMetrics struct { + // RED metrics + rec *metric.REDClient + + next SVC +} + +var _ SVC = (*mwMetrics)(nil) + +// MWMetrics is a metrics service middleware for the notification endpoint service. +func MWMetrics(reg *prom.Registry) SVCMiddleware { + return func(svc SVC) SVC { + return &mwMetrics{ + rec: metric.New(reg, "pkger"), + next: svc, + } + } +} + +func (s *mwMetrics) CreatePkg(ctx context.Context, setters ...CreatePkgSetFn) (*Pkg, error) { + rec := s.rec.Record("create_pkg") + pkg, err := s.next.CreatePkg(ctx, setters...) + return pkg, rec(err) +} + +func (s *mwMetrics) DryRun(ctx context.Context, orgID, userID influxdb.ID, pkg *Pkg) (Summary, Diff, error) { + rec := s.rec.Record("dry_run") + sum, diff, err := s.next.DryRun(ctx, orgID, userID, pkg) + return sum, diff, rec(err) +} + +func (s *mwMetrics) Apply(ctx context.Context, orgID, userID influxdb.ID, pkg *Pkg, opts ...ApplyOptFn) (Summary, error) { + rec := s.rec.Record("apply") + sum, err := s.next.Apply(ctx, orgID, userID, pkg, opts...) + return sum, rec(err) +}