Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metric View API Prototype #1473

Closed
wants to merge 11 commits into from
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Added

- Add `View` and `RegisterView` as part of the Metric API, and their implementation in the SDK. (#1473)

### Changed

- Reverse order in which `Resource` attributes are merged, per change in spec. (#1501)
- Moved `Aggregator`/`Aggregation`/`AggregatorSelector` interfaces to _otel/metric_ from _otel/sdk/export/metric_. (#1473)
- Support `KeyValue` labels with values unset. (#1473)
- Modified the `otel-collector` example to include View API usage. (#1473)
- `Accumulation` accepts a view selector for aggregator creation. (#1473)

## [0.16.0] - 2020-01-13

Expand Down
49 changes: 40 additions & 9 deletions example/otel-collector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
Expand Down Expand Up @@ -106,20 +107,40 @@ func main() {
tracer := otel.Tracer("test-tracer")
meter := otel.Meter("test-meter")

// Recorder metric example
vr, _ := meter.NewFloat64Counter(
"an_important_metric",
metric.WithDescription("Measures the cumulative epicness of the app"),
)

// DropAll view, meaning all records label would be dropped before aggregation.
meter.RegisterView(metric.NewView(vr.SyncImpl(), metric.DropAll, nil, nil))

// Ungroup view, meaning all records take the labels directly.
meter.RegisterView(metric.NewView(vr.SyncImpl(), metric.Ungroup, nil, nil))

// Two views with the same metric and aggregation type but different label keys for aggregation.
meter.RegisterView(metric.NewView(vr.SyncImpl(), metric.LabelKeys, []label.Key{"os_type"}, nil))
meter.RegisterView(metric.NewView(vr.SyncImpl(), metric.LabelKeys, []label.Key{"environment"}, nil))

// ValueRecorder histogram metric example
hist, _ := meter.NewFloat64ValueRecorder(
"example_hist",
metric.WithDescription("Example fixed bucket histogram"))

// Custom defined fixed bucket histogram aggregation
definedBuckets := []float64{1.0, 2.0, 3.0}
histogramAggregatorSelector := NewHistogramAggregationSelector(definedBuckets)
meter.RegisterView(metric.NewView(hist.SyncImpl(), metric.Ungroup, nil, histogramAggregatorSelector))

// labels represent additional key-value descriptors that can be bound to a
// metric observer or recorder.
commonLabels := []label.KeyValue{
label.String("labelA", "chocolate"),
label.String("labelB", "raspberry"),
label.String("labelC", "vanilla"),
label.String("os_type", "linux"),
}

// Recorder metric example
valuerecorder := metric.Must(meter).
NewFloat64Counter(
"an_important_metric",
metric.WithDescription("Measures the cumulative epicness of the app"),
).Bind(commonLabels...)
// Note: views registered after binding have no effect on the bind object.
valuerecorder := vr.Bind(commonLabels...)
defer valuerecorder.Unbind()

// work begins
Expand All @@ -133,6 +154,12 @@ func main() {
log.Printf("Doing really hard work (%d / 10)\n", i+1)
valuerecorder.Add(ctx, 1.0)

vr.Add(context.Background(), 1.0, label.String("os_type", "win"), label.String("environment", "prod"))

vr.Add(context.Background(), 1.0, label.String("environment", "ddev"))

hist.Record(context.Background(), float64(i%5))

<-time.After(time.Second)
iSpan.End()
}
Expand All @@ -145,3 +172,7 @@ func handleErr(err error, message string) {
log.Fatalf("%s: %v", message, err)
}
}

func NewHistogramAggregationSelector(buckets []float64) metric.AggregatorSelector {
return simple.NewWithHistogramDistribution(histogram.WithExplicitBoundaries(buckets))
}
2 changes: 1 addition & 1 deletion exporters/metric/prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/aggregation"
"go.opentelemetry.io/otel/metric/number"
export "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/internal/transform/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import (
resourcepb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/resource/v1"

"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric/aggregation"
"go.opentelemetry.io/otel/metric/number"
export "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/resource"
)
Expand Down
8 changes: 4 additions & 4 deletions exporters/otlp/internal/transform/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import (
metricpb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/metrics/v1"
"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/aggregation"
"go.opentelemetry.io/otel/metric/number"
export "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
"go.opentelemetry.io/otel/sdk/export/metric/metrictest"
arrAgg "go.opentelemetry.io/otel/sdk/metric/aggregator/exact"
"go.opentelemetry.io/otel/sdk/metric/aggregator/lastvalue"
Expand Down Expand Up @@ -328,10 +328,10 @@ func (t *testAgg) Aggregation() aggregation.Aggregation {
func (t *testAgg) Update(ctx context.Context, number number.Number, descriptor *metric.Descriptor) error {
return nil
}
func (t *testAgg) SynchronizedMove(destination export.Aggregator, descriptor *metric.Descriptor) error {
func (t *testAgg) SynchronizedMove(destination metric.Aggregator, descriptor *metric.Descriptor) error {
return nil
}
func (t *testAgg) Merge(aggregator export.Aggregator, descriptor *metric.Descriptor) error {
func (t *testAgg) Merge(aggregator metric.Aggregator, descriptor *metric.Descriptor) error {
return nil
}

Expand Down Expand Up @@ -373,7 +373,7 @@ func (te *testErrMinMaxSumCount) Count() (uint64, error) {
return 0, te.err
}

var _ export.Aggregator = &testAgg{}
var _ metric.Aggregator = &testAgg{}
var _ aggregation.Aggregation = &testAgg{}
var _ aggregation.Sum = &testErrSum{}
var _ aggregation.LastValue = &testErrLastValue{}
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/otlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import (
"sync"

"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/aggregation"
metricsdk "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
tracesdk "go.opentelemetry.io/otel/sdk/export/trace"
)

Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/otlp_metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import (
resourcepb "go.opentelemetry.io/otel/exporters/otlp/internal/opentelemetry-proto-gen/resource/v1"
"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/aggregation"
"go.opentelemetry.io/otel/metric/number"
metricsdk "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
"go.opentelemetry.io/otel/sdk/export/metric/metrictest"
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
"go.opentelemetry.io/otel/sdk/metric/aggregator/sum"
Expand Down Expand Up @@ -752,7 +752,7 @@ func runMetricExportTests(t *testing.T, opts []otlp.ExporterOption, rs []record,
desc := metric.NewDescriptor(r.name, r.iKind, r.nKind, r.opts...)
labs := label.NewSet(lcopy...)

var agg, ckpt metricsdk.Aggregator
var agg, ckpt metric.Aggregator
if r.iKind.Adding() {
agg, ckpt = metrictest.Unslice2(sum.New(2))
} else {
Expand Down
2 changes: 1 addition & 1 deletion exporters/stdout/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (

"go.opentelemetry.io/otel/label"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/aggregation"
exportmetric "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
)

type metricExporter struct {
Expand Down
2 changes: 1 addition & 1 deletion exporters/stdout/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestStdoutValueRecorderFormat(t *testing.T) {
func TestStdoutNoData(t *testing.T) {
desc := metric.NewDescriptor("test.name", metric.ValueRecorderInstrumentKind, number.Float64Kind)

runTwoAggs := func(agg, ckpt export.Aggregator) {
runTwoAggs := func(agg, ckpt metric.Aggregator) {
t.Run(fmt.Sprintf("%T", agg), func(t *testing.T) {
t.Parallel()

Expand Down
5 changes: 5 additions & 0 deletions internal/global/meter.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ func (m *meterImpl) setDelegate(name, version string, provider metric.MeterProvi
m.asyncInsts = nil
}

// RegisterView is a no-op here.
func (m *meterImpl) RegisterView(metric.View) {
// Should we panic here?
}

func (m *meterImpl) NewSyncInstrument(desc metric.Descriptor) (metric.SyncImpl, error) {
m.lock.Lock()
defer m.lock.Unlock()
Expand Down
12 changes: 12 additions & 0 deletions label/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ package label // import "go.opentelemetry.io/otel/label"
// allowed character set in the key depends on the use of the key.
type Key string

// Empty creates a KeyValue instance with value unset.
//
// Consider using a convenience function provided by the
// api/key package -
// key.Int64(name, value).
func (k Key) Empty() KeyValue {
return KeyValue{
Key: k,
Value: EmptyValue(),
}
}

// Bool creates a KeyValue instance with a BOOL Value.
//
// If creating both key and a bool value at the same time, then
Expand Down
5 changes: 5 additions & 0 deletions label/kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type KeyValue struct {
Value Value
}

// Empty creates an empty key-value pair with a passed name.
func Empty(k string) KeyValue {
return Key(k).Empty()
}

// Bool creates a new key-value pair with a passed name and a bool
// value.
func Bool(k string, v bool) KeyValue {
Expand Down
8 changes: 8 additions & 0 deletions label/kv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ func TestKeyValueConstructors(t *testing.T) {
actual label.KeyValue
expected label.KeyValue
}{
{
name: "Empty",
actual: label.Empty("k1"),
expected: label.KeyValue{
Key: "k1",
Value: label.EmptyValue(),
},
},
{
name: "Bool",
actual: label.Bool("k1", true),
Expand Down
7 changes: 7 additions & 0 deletions label/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ const (
ARRAY
)

// EmptyValue creates a Value with no value set.
func EmptyValue() Value {
return Value{
vtype: INVALID,
}
}

// BoolValue creates a BOOL Value.
func BoolValue(v bool) Value {
return Value{
Expand Down
6 changes: 6 additions & 0 deletions label/value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ func TestValue(t *testing.T) {
wantType label.Type
wantValue interface{}
}{
{
name: "Key.Empty() correctly returns key's internal empty value",
value: k.Empty().Value,
wantType: label.INVALID,
wantValue: nil,
},
{
name: "Key.Bool() correctly returns keys's internal bool value",
value: k.Bool(true).Value,
Expand Down
12 changes: 12 additions & 0 deletions metric/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ type Meter struct {
name, version string
}

// RegisterView registers a view for a synchronous instrument.
func (m Meter) RegisterView(v View) {
if m.impl != nil {
m.impl.RegisterView(v)
}
}

// RecordBatch atomically records a batch of measurements.
func (m Meter) RecordBatch(ctx context.Context, ls []label.KeyValue, ms ...Measurement) {
if m.impl == nil {
Expand Down Expand Up @@ -328,6 +335,11 @@ func Must(meter Meter) MeterMust {
return MeterMust{meter: meter}
}

// RegisterView calls `Meter.RegisterView`
func (mm MeterMust) RegisterView(v View) {
mm.meter.RegisterView(v)
}

// NewInt64Counter calls `Meter.NewInt64Counter` and returns the
// instrument, panicking if it encounters an error.
func (mm MeterMust) NewInt64Counter(name string, cos ...InstrumentOption) Int64Counter {
Expand Down
Loading