From a36d68219264b1cb94c0c83c1fdfab5315957015 Mon Sep 17 00:00:00 2001 From: Jonathan Amsterdam Date: Fri, 14 May 2021 13:49:26 -0400 Subject: [PATCH] event/otel: metrics Add an event handler for OpenTelemetry metrics. The first time it sees an event.Metric, the handler creates a matching otel instrument and caches it. On each call, it uses the instrument to record the metric value. Change-Id: I07d6f40601c7d2a801ed9fbe3cf7c24d5698f3f1 Reviewed-on: https://go-review.googlesource.com/c/exp/+/320350 Trust: Jonathan Amsterdam Run-TryBot: Jonathan Amsterdam TryBot-Result: Gopher Robot Reviewed-by: Ian Cottrell --- event/common.go | 2 +- event/event_test.go | 13 ++-- event/metric.go | 148 +++++++++++++++++--------------------- event/otel/metric.go | 131 +++++++++++++++++++++++++++++++++ event/otel/metric_test.go | 75 +++++++++++++++++++ go.mod | 6 +- go.sum | 30 ++------ jsonrpc2/defs.go | 19 +++-- 8 files changed, 301 insertions(+), 123 deletions(-) create mode 100644 event/otel/metric.go create mode 100644 event/otel/metric_test.go diff --git a/event/common.go b/event/common.go index 2bd82a4b6..f12b84a58 100644 --- a/event/common.go +++ b/event/common.go @@ -11,7 +11,7 @@ import ( ) const ( - MetricKey = "metric" + MetricKey = interfaceKey("metric") MetricVal = "metricValue" DurationMetric = interfaceKey("durationMetric") ) diff --git a/event/event_test.go b/event/event_test.go index d918bcda5..1757a976b 100644 --- a/event/event_test.go +++ b/event/event_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !disable_events // +build !disable_events package event_test @@ -24,9 +25,9 @@ var ( l1 = event.Int64("l1", 1) l2 = event.Int64("l2", 2) l3 = event.Int64("l3", 3) - counter = event.NewCounter("hits", "cache hits") - gauge = event.NewFloatGauge("temperature", "CPU board temperature in Celsius") - latency = event.NewDuration("latency", "how long it took") + counter = event.NewCounter("hits", nil) + gauge = event.NewFloatGauge("temperature", nil) + latency = event.NewDuration("latency", nil) err = errors.New("an error") ) @@ -275,7 +276,7 @@ func (t *testTraceHandler) Event(ctx context.Context, ev *event.Event) context.C func TestTraceDuration(t *testing.T) { // Verify that a trace can can emit a latency metric. - dur := event.NewDuration("test", "") + dur := event.NewDuration("test", nil) want := time.Second check := func(t *testing.T, h *testTraceDurationHandler) { @@ -313,7 +314,7 @@ type testTraceDurationHandler struct { func (t *testTraceDurationHandler) Event(ctx context.Context, ev *event.Event) context.Context { for _, l := range ev.Labels { - if l.Name == event.MetricVal { + if l.Name == string(event.MetricVal) { t.got = l } } @@ -322,7 +323,7 @@ func (t *testTraceDurationHandler) Event(ctx context.Context, ev *event.Event) c func BenchmarkBuildContext(b *testing.B) { // How long does it take to deliver an event from a nested context? - c := event.NewCounter("c", "") + c := event.NewCounter("c", nil) for _, depth := range []int{1, 5, 7, 10} { b.Run(fmt.Sprintf("depth %d", depth), func(b *testing.B) { ctx := event.WithExporter(context.Background(), event.NewExporter(nopHandler{}, eventtest.ExporterOptions())) diff --git a/event/metric.go b/event/metric.go index a603a1099..e74689e57 100644 --- a/event/metric.go +++ b/event/metric.go @@ -6,81 +6,71 @@ package event import ( "context" - "fmt" "time" ) +// A Unit is a unit of measurement for a metric. +type Unit string + +const ( + UnitDimensionless Unit = "1" + UnitBytes Unit = "By" + UnitMilliseconds Unit = "ms" +) + // A Metric represents a kind of recorded measurement. type Metric interface { - Descriptor() *MetricDescriptor + Name() string + Options() MetricOptions } -// A MetricDescriptor describes a metric. -type MetricDescriptor struct { - namespace string - name string - description string - // TODO: deal with units. Follow otel, or define Go types for common units. - // We don't need a time unit because we'll use time.Duration, and the only - // other unit otel currently defines (besides dimensionless) is bytes. +type MetricOptions struct { + // A string that should be common for all metrics of an application or + // service. Defaults to the import path of the package calling + // the metric construction function (NewCounter, etc.). + Namespace string + + // Optional description of the metric. + Description string + + // Optional unit for the metric. Defaults to UnitDimensionless. + Unit Unit } -// NewMetricDescriptor creates a MetricDescriptor with the given name. -// The namespace defaults to the import path of the caller of NewMetricDescriptor. -// Use SetNamespace to provide a different one. -// Neither the name nor the namespace can be empty. -func NewMetricDescriptor(name, description string) *MetricDescriptor { - return newMetricDescriptor(name, description) +// A Counter is a metric that counts something cumulatively. +type Counter struct { + name string + opts MetricOptions } -func newMetricDescriptor(name, description string) *MetricDescriptor { - if name == "" { - panic("name cannot be empty") +func initOpts(popts *MetricOptions) MetricOptions { + var opts MetricOptions + if popts != nil { + opts = *popts } - return &MetricDescriptor{ - name: name, - namespace: scanStack().Space, - description: description, + if opts.Namespace == "" { + opts.Namespace = scanStack().Space } -} - -// SetNamespace sets the namespace of m to a non-empty string. -func (m *MetricDescriptor) SetNamespace(ns string) { - if ns == "" { - panic("namespace cannot be empty") + if opts.Unit == "" { + opts.Unit = UnitDimensionless } - m.namespace = ns -} - -func (m *MetricDescriptor) String() string { - return fmt.Sprintf("Metric(\"%s/%s\")", m.namespace, m.name) -} - -func (m *MetricDescriptor) Name() string { return m.name } -func (m *MetricDescriptor) Namespace() string { return m.namespace } -func (m *MetricDescriptor) Description() string { return m.description } - -// A Counter is a metric that counts something cumulatively. -type Counter struct { - *MetricDescriptor + return opts } // NewCounter creates a counter with the given name. -func NewCounter(name, description string) *Counter { - return &Counter{newMetricDescriptor(name, description)} +func NewCounter(name string, opts *MetricOptions) *Counter { + return &Counter{name, initOpts(opts)} } -// Descriptor returns the receiver's MetricDescriptor. -func (c *Counter) Descriptor() *MetricDescriptor { - return c.MetricDescriptor -} +func (c *Counter) Name() string { return c.name } +func (c *Counter) Options() MetricOptions { return c.opts } // Record delivers a metric event with the given metric, value and labels to the // exporter in the context. func (c *Counter) Record(ctx context.Context, v int64, labels ...Label) { ev := New(ctx, MetricKind) if ev != nil { - record(ev, c, Int64(MetricVal, v)) + record(ev, c, Int64(string(MetricVal), v)) ev.Labels = append(ev.Labels, labels...) ev.Deliver() } @@ -89,26 +79,24 @@ func (c *Counter) Record(ctx context.Context, v int64, labels ...Label) { // A FloatGauge records a single floating-point value that may go up or down. // TODO(generics): Gauge[T] type FloatGauge struct { - *MetricDescriptor + name string + opts MetricOptions } // NewFloatGauge creates a new FloatGauge with the given name. -func NewFloatGauge(name, description string) *FloatGauge { - return &FloatGauge{newMetricDescriptor(name, description)} +func NewFloatGauge(name string, opts *MetricOptions) *FloatGauge { + return &FloatGauge{name, initOpts(opts)} } -// Descriptor returns the receiver's MetricDescriptor. -func (g *FloatGauge) Descriptor() *MetricDescriptor { - return g.MetricDescriptor -} +func (g *FloatGauge) Name() string { return g.name } +func (g *FloatGauge) Options() MetricOptions { return g.opts } // Record converts its argument into a Value and returns a MetricValue with the -// receiver and the value. It is intended to be used as an argument to -// Builder.Metric. +// receiver and the value. func (g *FloatGauge) Record(ctx context.Context, v float64, labels ...Label) { ev := New(ctx, MetricKind) if ev != nil { - record(ev, g, Float64(MetricVal, v)) + record(ev, g, Float64(string(MetricVal), v)) ev.Labels = append(ev.Labels, labels...) ev.Deliver() } @@ -117,26 +105,24 @@ func (g *FloatGauge) Record(ctx context.Context, v float64, labels ...Label) { // A DurationDistribution records a distribution of durations. // TODO(generics): Distribution[T] type DurationDistribution struct { - *MetricDescriptor + name string + opts MetricOptions } // NewDuration creates a new Duration with the given name. -func NewDuration(name, description string) *DurationDistribution { - return &DurationDistribution{newMetricDescriptor(name, description)} +func NewDuration(name string, opts *MetricOptions) *DurationDistribution { + return &DurationDistribution{name, initOpts(opts)} } -// Descriptor returns the receiver's MetricDescriptor. -func (d *DurationDistribution) Descriptor() *MetricDescriptor { - return d.MetricDescriptor -} +func (d *DurationDistribution) Name() string { return d.name } +func (d *DurationDistribution) Options() MetricOptions { return d.opts } // Record converts its argument into a Value and returns a MetricValue with the -// receiver and the value. It is intended to be used as an argument to -// Builder.Metric. +// receiver and the value. func (d *DurationDistribution) Record(ctx context.Context, v time.Duration, labels ...Label) { ev := New(ctx, MetricKind) if ev != nil { - record(ev, d, Duration(MetricVal, v)) + record(ev, d, Duration(string(MetricVal), v)) ev.Labels = append(ev.Labels, labels...) ev.Deliver() } @@ -144,31 +130,29 @@ func (d *DurationDistribution) Record(ctx context.Context, v time.Duration, labe // An IntDistribution records a distribution of int64s. type IntDistribution struct { - *MetricDescriptor + name string + opts MetricOptions } -// NewIntDistribution creates a new IntDistribution with the given name. -func NewIntDistribution(name, description string) *IntDistribution { - return &IntDistribution{newMetricDescriptor(name, description)} -} +func (d *IntDistribution) Name() string { return d.name } +func (d *IntDistribution) Options() MetricOptions { return d.opts } -// Descriptor returns the receiver's MetricDescriptor. -func (d *IntDistribution) Descriptor() *MetricDescriptor { - return d.MetricDescriptor +// NewIntDistribution creates a new IntDistribution with the given name. +func NewIntDistribution(name string, opts *MetricOptions) *IntDistribution { + return &IntDistribution{name, initOpts(opts)} } // Record converts its argument into a Value and returns a MetricValue with the -// receiver and the value. It is intended to be used as an argument to -// Builder.Metric. +// receiver and the value. func (d *IntDistribution) Record(ctx context.Context, v int64, labels ...Label) { ev := New(ctx, MetricKind) if ev != nil { - record(ev, d, Int64(MetricVal, v)) + record(ev, d, Int64(string(MetricVal), v)) ev.Labels = append(ev.Labels, labels...) ev.Deliver() } } func record(ev *Event, m Metric, l Label) { - ev.Labels = append(ev.Labels, l, Value(MetricKey, m)) + ev.Labels = append(ev.Labels, l, MetricKey.Of(m)) } diff --git a/event/otel/metric.go b/event/otel/metric.go new file mode 100644 index 000000000..910cc949b --- /dev/null +++ b/event/otel/metric.go @@ -0,0 +1,131 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package otel + +import ( + "context" + "errors" + "fmt" + "sync" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + otelunit "go.opentelemetry.io/otel/metric/unit" + "golang.org/x/exp/event" +) + +// MetricHandler is an event.Handler for OpenTelemetry metrics. +// Its Event method handles Metric events and ignores all others. +type MetricHandler struct { + meter metric.MeterMust + mu sync.Mutex + // A map from event.Metrics to, effectively, otel Meters. + // But since the only thing we need from the Meter is recording a value, we + // use a function for that that closes over the Meter itself. + recordFuncs map[event.Metric]recordFunc +} + +type recordFunc func(context.Context, event.Label, []attribute.KeyValue) + +var _ event.Handler = (*MetricHandler)(nil) + +// NewMetricHandler creates a new MetricHandler. +func NewMetricHandler(m metric.Meter) *MetricHandler { + return &MetricHandler{ + meter: metric.Must(m), + recordFuncs: map[event.Metric]recordFunc{}, + } +} + +func (m *MetricHandler) Event(ctx context.Context, e *event.Event) context.Context { + if e.Kind != event.MetricKind { + return ctx + } + // Get the otel instrument corresponding to the event's MetricDescriptor, + // or create a new one. + mi, ok := event.MetricKey.Find(e) + if !ok { + panic(errors.New("no metric key for metric event")) + } + em := mi.(event.Metric) + lval := e.Find(event.MetricVal) + if !lval.HasValue() { + panic(errors.New("no metric value for metric event")) + } + rf := m.getRecordFunc(em) + if rf == nil { + panic(fmt.Errorf("unable to record for metric %v", em)) + } + rf(ctx, lval, labelsToAttributes(e.Labels)) + return ctx +} + +func (m *MetricHandler) getRecordFunc(em event.Metric) recordFunc { + m.mu.Lock() + defer m.mu.Unlock() + if f, ok := m.recordFuncs[em]; ok { + return f + } + f := m.newRecordFunc(em) + m.recordFuncs[em] = f + return f +} + +func (m *MetricHandler) newRecordFunc(em event.Metric) recordFunc { + opts := em.Options() + name := opts.Namespace + "/" + em.Name() + otelOpts := []metric.InstrumentOption{ + metric.WithDescription(opts.Description), + metric.WithUnit(otelunit.Unit(opts.Unit)), // cast OK: same strings + } + switch em.(type) { + case *event.Counter: + c := m.meter.NewInt64Counter(name, otelOpts...) + return func(ctx context.Context, l event.Label, attrs []attribute.KeyValue) { + c.Add(ctx, l.Int64(), attrs...) + } + + case *event.FloatGauge: + g := m.meter.NewFloat64UpDownCounter(name, otelOpts...) + return func(ctx context.Context, l event.Label, attrs []attribute.KeyValue) { + g.Add(ctx, l.Float64(), attrs...) + } + + case *event.DurationDistribution: + r := m.meter.NewInt64Histogram(name, otelOpts...) + return func(ctx context.Context, l event.Label, attrs []attribute.KeyValue) { + r.Record(ctx, l.Duration().Nanoseconds(), attrs...) + } + + default: + return nil + } +} + +func labelsToAttributes(ls []event.Label) []attribute.KeyValue { + var attrs []attribute.KeyValue + for _, l := range ls { + if l.Name == string(event.MetricKey) || l.Name == string(event.MetricVal) { + continue + } + attrs = append(attrs, labelToAttribute(l)) + } + return attrs +} + +func labelToAttribute(l event.Label) attribute.KeyValue { + switch { + case l.IsString(): + return attribute.String(l.Name, l.String()) + case l.IsInt64(): + return attribute.Int64(l.Name, l.Int64()) + case l.IsFloat64(): + return attribute.Float64(l.Name, l.Float64()) + case l.IsBool(): + return attribute.Bool(l.Name, l.Bool()) + default: // including uint64 + panic(fmt.Errorf("cannot convert label value of type %T to attribute.KeyValue", l.Interface())) + } +} diff --git a/event/otel/metric_test.go b/event/otel/metric_test.go new file mode 100644 index 000000000..300f4a732 --- /dev/null +++ b/event/otel/metric_test.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package otel_test + +import ( + "context" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric/metrictest" + "go.opentelemetry.io/otel/metric/number" + "golang.org/x/exp/event" + "golang.org/x/exp/event/otel" +) + +func TestMeter(t *testing.T) { + ctx := context.Background() + mp := metrictest.NewMeterProvider() + mh := otel.NewMetricHandler(mp.Meter("test")) + ctx = event.WithExporter(ctx, event.NewExporter(mh, nil)) + recordMetrics(ctx) + + lib := metrictest.Library{InstrumentationName: "test"} + emptyLabels := map[attribute.Key]attribute.Value{} + got := metrictest.AsStructs(mp.MeasurementBatches) + want := []metrictest.Measured{ + { + Name: "golang.org/x/exp/event/otel_test/hits", + Number: number.NewInt64Number(8), + Labels: emptyLabels, + Library: lib, + }, + { + Name: "golang.org/x/exp/event/otel_test/temp", + Number: number.NewFloat64Number(-100), + Labels: map[attribute.Key]attribute.Value{"location": attribute.StringValue("Mare Imbrium")}, + Library: lib, + }, + { + Name: "golang.org/x/exp/event/otel_test/latency", + Number: number.NewInt64Number(int64(1248 * time.Millisecond)), + Labels: emptyLabels, + Library: lib, + }, + { + Name: "golang.org/x/exp/event/otel_test/latency", + Number: number.NewInt64Number(int64(1255 * time.Millisecond)), + Labels: emptyLabels, + Library: lib, + }, + } + + if diff := cmp.Diff(want, got, cmp.Comparer(valuesEqual)); diff != "" { + t.Errorf("mismatch (-want, got):\n%s", diff) + } +} + +func valuesEqual(v1, v2 attribute.Value) bool { + return v1.AsInterface() == v2.AsInterface() +} + +func recordMetrics(ctx context.Context) { + c := event.NewCounter("hits", &event.MetricOptions{Description: "Earth meteorite hits"}) + g := event.NewFloatGauge("temp", &event.MetricOptions{Description: "moon surface temperature in Kelvin"}) + d := event.NewDuration("latency", &event.MetricOptions{Description: "Earth-moon comms lag, milliseconds"}) + + c.Record(ctx, 8) + g.Record(ctx, -100, event.String("location", "Mare Imbrium")) + d.Record(ctx, 1248*time.Millisecond) + d.Record(ctx, 1255*time.Millisecond) +} diff --git a/go.mod b/go.mod index 7cd7c67c6..cc530ad9e 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,8 @@ require ( github.com/google/go-cmp v0.5.6 github.com/rs/zerolog v1.21.0 github.com/sirupsen/logrus v1.8.1 + go.opentelemetry.io/otel v1.3.0 + go.opentelemetry.io/otel/metric v0.26.0 go.opentelemetry.io/otel/sdk v1.3.0 go.opentelemetry.io/otel/trace v1.3.0 go.uber.org/zap v1.16.0 @@ -25,10 +27,8 @@ require ( require ( github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/go-logr/stdr v1.2.0 // indirect - go.opentelemetry.io/otel v1.3.0 // indirect - go.opentelemetry.io/otel/metric v0.20.0 // indirect + go.opentelemetry.io/otel/internal/metric v0.26.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect honnef.co/go/tools v0.1.3 // indirect ) - diff --git a/go.sum b/go.sum index d7654bdb4..1445e4698 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= @@ -97,8 +95,6 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -259,26 +255,19 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= -go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/internal/metric v0.26.0 h1:dlrvawyd/A+X8Jp0EBT4wWEe4k5avYaXsXrBr4dbfnY= +go.opentelemetry.io/otel/internal/metric v0.26.0/go.mod h1:CbBP6AxKynRs3QCbhklyLUtpfzbqCLiafV9oY2Zj1Jk= +go.opentelemetry.io/otel/metric v0.26.0 h1:VaPYBTvA13h/FsiWfxa3yZnZEm15BhStD8JZQSA773M= +go.opentelemetry.io/otel/metric v0.26.0/go.mod h1:c6YL0fhRo4YVoNs6GoByzUgBp36hBL523rECoZA5UWg= go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= -go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY= go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -303,7 +292,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -323,7 +311,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -343,8 +330,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -354,7 +339,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -372,19 +356,13 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/jsonrpc2/defs.go b/jsonrpc2/defs.go index 80b25c1a1..e3677de7b 100644 --- a/jsonrpc2/defs.go +++ b/jsonrpc2/defs.go @@ -14,11 +14,20 @@ func RPCDirection(v string) event.Label { return event.String("direction", v) } func StatusCode(v string) event.Label { return event.String("status.code", v) } var ( - Started = event.NewCounter("started", "Count of started RPCs.") - Finished = event.NewCounter("finished", "Count of finished RPCs (includes error).") - ReceivedBytes = event.NewIntDistribution("received_bytes", "Bytes received.") //, unit.Bytes) - SentBytes = event.NewIntDistribution("sent_bytes", "Bytes sent.") //, unit.Bytes) - Latency = event.NewDuration("latency", "Elapsed time of an RPC.") //, unit.Milliseconds) + Started = event.NewCounter("started", &event.MetricOptions{Description: "Count of started RPCs."}) + Finished = event.NewCounter("finished", &event.MetricOptions{Description: "Count of finished RPCs (includes error)."}) + ReceivedBytes = event.NewIntDistribution("received_bytes", &event.MetricOptions{ + Description: "Bytes received.", + Unit: event.UnitBytes, + }) + SentBytes = event.NewIntDistribution("sent_bytes", &event.MetricOptions{ + Description: "Bytes sent.", + Unit: event.UnitBytes, + }) + Latency = event.NewDuration("latency", &event.MetricOptions{ + Description: "Elapsed time of an RPC.", + Unit: event.UnitMilliseconds, + }) ) const (