From 6bfa16ecef9e41bcafbe4c4bd2f822bd7c2337df Mon Sep 17 00:00:00 2001 From: Ahmed Mujtaba Date: Sat, 2 May 2020 23:56:08 +0200 Subject: [PATCH 01/21] Added test case for grpc UrinaryInterceptorClient --- plugin/grpctrace/interceptor_test.go | 141 ++++++++++++--------------- 1 file changed, 65 insertions(+), 76 deletions(-) diff --git a/plugin/grpctrace/interceptor_test.go b/plugin/grpctrace/interceptor_test.go index d9360341d..8c5ec6f69 100644 --- a/plugin/grpctrace/interceptor_test.go +++ b/plugin/grpctrace/interceptor_test.go @@ -20,6 +20,8 @@ import ( "google.golang.org/grpc" + "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/global" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -32,110 +34,97 @@ func (t *testExporter) ExportSpan(ctx context.Context, s *export.SpanData) { t.spanMap[s.Name] = append(t.spanMap[s.Name], s) } -type mockCCInvoker struct { +type mockUICInvoker struct { ctx context.Context } -func (mcci *mockCCInvoker) invoke(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error { - mcci.ctx = ctx +func (mcuici *mockUICInvoker) invoker(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error { + mcuici.ctx = ctx return nil } -type mockProtoMessage struct { +type mockProtoMessage struct{} + +func (mm *mockProtoMessage) Reset() { } -func (mm *mockProtoMessage) Reset() {} -func (mm *mockProtoMessage) String() string { return "mock" } -func (mm *mockProtoMessage) ProtoMessage() {} - -type nameAttributeTestCase struct { - testName string - expectedName string - fullNameFmt string +func (mm *mockProtoMessage) String() string { + return "mock" } -func (tc nameAttributeTestCase) fullName() string { - return fmt.Sprintf(tc.fullNameFmt, tc.expectedName) +func (mm *mockProtoMessage) ProtoMessage() { } -func TestUCISetsExpectedServiceNameAttribute(t *testing.T) { - testCases := []nameAttributeTestCase{ - { - "FullyQualifiedMethodName", - "serviceName", - "/github.com.foo.%s/bar", - }, - { - "SimpleMethodName", - "serviceName", - "/%s/bar", - }, - { - "MethodNameWithoutFullPath", - "serviceName", - "%s/bar", - }, - { - "InvalidMethodName", - "", - "invalidName", - }, - { - "NonAlphanumericMethodName", - "serviceName_123", - "/github.com.foo.%s/method", - }, - } - - for _, tc := range testCases { - t.Run(tc.testName, tc.testUCISetsExpectedNameAttribute) - } -} - -func (tc nameAttributeTestCase) testUCISetsExpectedNameAttribute(t *testing.T) { +func TestUnaryClientInterceptor(t *testing.T) { exp := &testExporter{make(map[string][]*export.SpanData)} tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp), - sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()})) - - tr := tp.Tracer("grpctrace/client") - ctx, span := tr.Start(context.Background(), tc.testName) - defer span.End() + sdktrace.WithConfig(sdktrace.Config{ + DefaultSampler: sdktrace.AlwaysSample(), + }, + )) + global.SetTraceProvider(tp) clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure()) - if err != nil { t.Fatalf("failed to create client connection: %v", err) } - unaryInt := UnaryClientInterceptor(tr) + tracer := tp.Tracer("grpctrace/client") + unaryInterceptor := UnaryClientInterceptor(tracer) req := &mockProtoMessage{} reply := &mockProtoMessage{} - ccInvoker := &mockCCInvoker{} + uniInterceptorInvoker := &mockUICInvoker{} - err = unaryInt(ctx, tc.fullName(), req, reply, clientConn, ccInvoker.invoke) - if err != nil { - t.Fatalf("failed to run unary interceptor: %v", err) + checks := []struct { + name string + expectedAttr map[core.Key]core.Value + eventsAttr [][]core.KeyValue + }{ + { + name: fmt.Sprintf("/foo.%s/bar", "serviceName"), + expectedAttr: map[core.Key]core.Value{ + rpcServiceKey: core.String("serviceName"), + netPeerIPKey: core.String("fake"), + netPeerPortKey: core.String("connection"), + }, + eventsAttr: [][]core.KeyValue{ + { + core.KeyValue{Key: messageTypeKey, Value: core.String("SENT")}, + core.KeyValue{Key: messageIDKey, Value: core.Int(1)}, + }, + { + core.KeyValue{Key: messageTypeKey, Value: core.String("RECEIVED")}, + core.KeyValue{Key: messageIDKey, Value: core.Int(1)}, + }, + }, + }, } - spanData, hasSpanData := exp.spanMap[tc.fullName()] + for _, check := range checks { + err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker) + if err != nil { + t.Fatalf("failed to run unary interceptor: %v", err) + } - if !hasSpanData || len(spanData) == 0 { - t.Fatalf("no span data found for name < %s >", tc.fullName()) - } + attrs := exp.spanMap[check.name][0].Attributes + for _, attr := range attrs { + expectedAttr, ok := check.expectedAttr[attr.Key] + if ok { + if expectedAttr != attr.Value { + t.Fatalf("invalid %s found. expected %s, actual %s", string(attr.Key), + expectedAttr.AsString(), attr.Value.AsString()) + } + } + } - attributes := spanData[0].Attributes - - var actualServiceName string - for _, attr := range attributes { - if attr.Key == rpcServiceKey { - actualServiceName = attr.Value.AsString() - break + events := exp.spanMap[check.name][0].MessageEvents + for event := 0; event < len(check.eventsAttr); event++ { + for attr := 0; attr < len(check.eventsAttr[event]); attr++ { + if events[event].Attributes[attr] != check.eventsAttr[event][attr] { + t.Fatalf("invalid attribute in events") + } + } } } - - if tc.expectedName != actualServiceName { - t.Fatalf("invalid service name found. expected %s, actual %s", - tc.expectedName, actualServiceName) - } } From 02ff1be72ccc4447c17b88816c20d71d43536419 Mon Sep 17 00:00:00 2001 From: Ahmed Mujtaba Date: Tue, 5 May 2020 22:50:01 +0200 Subject: [PATCH 02/21] Minor fixes and improvment in GRPC urinary interceptor test --- plugin/grpctrace/interceptor_test.go | 82 ++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/plugin/grpctrace/interceptor_test.go b/plugin/grpctrace/interceptor_test.go index 8c5ec6f69..fac424933 100644 --- a/plugin/grpctrace/interceptor_test.go +++ b/plugin/grpctrace/interceptor_test.go @@ -21,7 +21,6 @@ import ( "google.golang.org/grpc" "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/global" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -62,7 +61,6 @@ func TestUnaryClientInterceptor(t *testing.T) { DefaultSampler: sdktrace.AlwaysSample(), }, )) - global.SetTraceProvider(tp) clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure()) if err != nil { @@ -79,50 +77,102 @@ func TestUnaryClientInterceptor(t *testing.T) { checks := []struct { name string expectedAttr map[core.Key]core.Value - eventsAttr [][]core.KeyValue + eventsAttr []map[core.Key]core.Value }{ { - name: fmt.Sprintf("/foo.%s/bar", "serviceName"), + name: "/github.com.serviceName/bar", expectedAttr: map[core.Key]core.Value{ rpcServiceKey: core.String("serviceName"), netPeerIPKey: core.String("fake"), netPeerPortKey: core.String("connection"), }, - eventsAttr: [][]core.KeyValue{ + eventsAttr: []map[core.Key]core.Value{ { - core.KeyValue{Key: messageTypeKey, Value: core.String("SENT")}, - core.KeyValue{Key: messageIDKey, Value: core.Int(1)}, + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), }, { - core.KeyValue{Key: messageTypeKey, Value: core.String("RECEIVED")}, - core.KeyValue{Key: messageIDKey, Value: core.Int(1)}, + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), }, }, }, + { + name: "/serviceName/bar", + expectedAttr: map[core.Key]core.Value{ + rpcServiceKey: core.String("serviceName"), + }, + eventsAttr: []map[core.Key]core.Value{ + { + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), + }, + { + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), + }, + }, + }, + { + name: "serviceName/bar", + expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName")}, + }, + { + name: "invalidName", + expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("")}, + }, + { + name: "/github.com.foo.serviceName_123/method", + expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName_123")}, + }, } - for _, check := range checks { + for idx, check := range checks { + fmt.Println("================", idx, "==================") err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker) if err != nil { t.Fatalf("failed to run unary interceptor: %v", err) } - attrs := exp.spanMap[check.name][0].Attributes + spanData, ok := exp.spanMap[check.name] + if !ok || len(spanData) == 0 { + t.Fatalf("no span data found for name < %s >", check.name) + } + + attrs := spanData[0].Attributes for _, attr := range attrs { expectedAttr, ok := check.expectedAttr[attr.Key] if ok { if expectedAttr != attr.Value { - t.Fatalf("invalid %s found. expected %s, actual %s", string(attr.Key), + t.Errorf("name: %s invalid %s found. expected %s, actual %s", check.name, string(attr.Key), expectedAttr.AsString(), attr.Value.AsString()) } + delete(check.expectedAttr, attr.Key) } } - events := exp.spanMap[check.name][0].MessageEvents + // Check if any expected attr not seen + if len(check.expectedAttr) > 0 { + for attr := range check.expectedAttr { + t.Errorf("missing attribute %s in span", string(attr)) + } + } + + events := spanData[0].MessageEvents for event := 0; event < len(check.eventsAttr); event++ { - for attr := 0; attr < len(check.eventsAttr[event]); attr++ { - if events[event].Attributes[attr] != check.eventsAttr[event][attr] { - t.Fatalf("invalid attribute in events") + for _, attr := range events[event].Attributes { + expectedAttr, ok := check.eventsAttr[event][attr.Key] + if ok { + if attr.Value != expectedAttr { + t.Errorf("invalid value for attribute %s in events, expected %s actual %s", + string(attr.Key), attr.Value.AsString(), expectedAttr.AsString()) + } + delete(check.eventsAttr[event], attr.Key) + } + } + if len(check.eventsAttr[event]) > 0 { + for attr := range check.eventsAttr[event] { + t.Errorf("missing attribute %s in span event", string(attr)) } } } From cffc57c907a4d002057e688ad4f62097eabc876d Mon Sep 17 00:00:00 2001 From: Ahmed Mujtaba Date: Sun, 10 May 2020 23:19:20 +0200 Subject: [PATCH 03/21] Added grpc stream interceptor client --- plugin/grpctrace/interceptor_test.go | 133 ++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/plugin/grpctrace/interceptor_test.go b/plugin/grpctrace/interceptor_test.go index fac424933..2dce41797 100644 --- a/plugin/grpctrace/interceptor_test.go +++ b/plugin/grpctrace/interceptor_test.go @@ -15,10 +15,12 @@ package grpctrace import ( "context" - "fmt" + "sync" "testing" + "time" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "go.opentelemetry.io/otel/api/core" export "go.opentelemetry.io/otel/sdk/export/trace" @@ -26,10 +28,13 @@ import ( ) type testExporter struct { + mu sync.Mutex spanMap map[string][]*export.SpanData } func (t *testExporter) ExportSpan(ctx context.Context, s *export.SpanData) { + t.mu.Lock() + defer t.mu.Unlock() t.spanMap[s.Name] = append(t.spanMap[s.Name], s) } @@ -55,7 +60,7 @@ func (mm *mockProtoMessage) ProtoMessage() { } func TestUnaryClientInterceptor(t *testing.T) { - exp := &testExporter{make(map[string][]*export.SpanData)} + exp := &testExporter{spanMap: make(map[string][]*export.SpanData)} tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp), sdktrace.WithConfig(sdktrace.Config{ DefaultSampler: sdktrace.AlwaysSample(), @@ -127,8 +132,7 @@ func TestUnaryClientInterceptor(t *testing.T) { }, } - for idx, check := range checks { - fmt.Println("================", idx, "==================") + for _, check := range checks { err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker) if err != nil { t.Fatalf("failed to run unary interceptor: %v", err) @@ -178,3 +182,124 @@ func TestUnaryClientInterceptor(t *testing.T) { } } } + +type mockClientStream struct { + Desc *grpc.StreamDesc + Ctx context.Context +} + +func (mockClientStream) SendMsg(m interface{}) error { return nil } +func (mockClientStream) RecvMsg(m interface{}) error { return nil } +func (mockClientStream) CloseSend() error { return nil } +func (c mockClientStream) Context() context.Context { return c.Ctx } +func (mockClientStream) Header() (metadata.MD, error) { return nil, nil } +func (mockClientStream) Trailer() metadata.MD { return nil } + +func TestStreamClientInterceptor(t *testing.T) { + exp := &testExporter{spanMap: make(map[string][]*export.SpanData)} + tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp), + sdktrace.WithConfig(sdktrace.Config{ + DefaultSampler: sdktrace.AlwaysSample(), + }, + )) + clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure()) + if err != nil { + t.Fatalf("failed to create client connection: %v", err) + } + + // tracer + tracer := tp.Tracer("grpctrace/Server") + streamCI := StreamClientInterceptor(tracer) + + var mockClStr mockClientStream + methodName := "/github.com.serviceName/bar" + + streamClient, err := streamCI(context.Background(), + &grpc.StreamDesc{ServerStreams: true}, + clientConn, + methodName, + func(ctx context.Context, + desc *grpc.StreamDesc, + cc *grpc.ClientConn, + method string, + opts ...grpc.CallOption) (grpc.ClientStream, error) { + mockClStr = mockClientStream{Desc: desc, Ctx: ctx} + return mockClStr, nil + }) + + if err != nil { + t.Fatalf("failed to initialize grpc stream client: %v", err) + } + + // no span exported while stream is open + if _, ok := exp.spanMap[methodName]; ok { + t.Fatalf("span shouldn't end while stream is open") + } + + req := &mockProtoMessage{} + reply := &mockProtoMessage{} + + // send and receive fake data + for i := 0; i < 10; i++ { + _ = streamClient.SendMsg(req) + _ = streamClient.RecvMsg(reply) + } + + // close client and server stream + _ = streamClient.CloseSend() + mockClStr.Desc.ServerStreams = false + _ = streamClient.RecvMsg(reply) + + // added retry because span end is called in separate go routine + var spanData []*export.SpanData + for retry := 0; retry < 5; retry++ { + ok := false + exp.mu.Lock() + spanData, ok = exp.spanMap[methodName] + exp.mu.Unlock() + if ok { + break + } + time.Sleep(time.Second * 1) + } + if len(spanData) == 0 { + t.Fatalf("no span data found for name < %s >", methodName) + } + + attrs := spanData[0].Attributes + expectedAttr := map[core.Key]string{ + rpcServiceKey: "serviceName", + netPeerIPKey: "fake", + netPeerPortKey: "connection", + } + + for _, attr := range attrs { + expected, ok := expectedAttr[attr.Key] + if ok { + if expected != attr.Value.AsString() { + t.Errorf("name: %s invalid %s found. expected %s, actual %s", methodName, string(attr.Key), + expected, attr.Value.AsString()) + } + } + } + + events := spanData[0].MessageEvents + if len(events) != 20 { + t.Fatalf("incorrect number of events expected 20 got %d", len(events)) + } + for i := 0; i < 20; i += 2 { + msgID := i/2 + 1 + validate := func(eventName string, attrs []core.KeyValue) { + for _, attr := range attrs { + if attr.Key == messageTypeKey && attr.Value.AsString() != eventName { + t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, attr.Value.AsString()) + } + if attr.Key == messageIDKey && attr.Value != core.Int(msgID) { + t.Errorf("invalid id for message event expected %d received %d", msgID, attr.Value.AsInt32()) + } + } + } + validate("SENT", events[i].Attributes) + validate("RECEIVED", events[i+1].Attributes) + } +} From c40b3d47cf4aa0f024140013041607a41f184325 Mon Sep 17 00:00:00 2001 From: Ahmed Mujtaba Date: Wed, 13 May 2020 19:43:20 +0200 Subject: [PATCH 04/21] minor improvements in grpc interceptor test --- plugin/grpctrace/interceptor_test.go | 36 ++++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/plugin/grpctrace/interceptor_test.go b/plugin/grpctrace/interceptor_test.go index 2dce41797..3667b9dbe 100644 --- a/plugin/grpctrace/interceptor_test.go +++ b/plugin/grpctrace/interceptor_test.go @@ -29,13 +29,13 @@ import ( type testExporter struct { mu sync.Mutex - spanMap map[string][]*export.SpanData + spanMap map[string]*export.SpanData } func (t *testExporter) ExportSpan(ctx context.Context, s *export.SpanData) { t.mu.Lock() defer t.mu.Unlock() - t.spanMap[s.Name] = append(t.spanMap[s.Name], s) + t.spanMap[s.Name] = s } type mockUICInvoker struct { @@ -60,7 +60,7 @@ func (mm *mockProtoMessage) ProtoMessage() { } func TestUnaryClientInterceptor(t *testing.T) { - exp := &testExporter{spanMap: make(map[string][]*export.SpanData)} + exp := &testExporter{spanMap: make(map[string]*export.SpanData)} tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp), sdktrace.WithConfig(sdktrace.Config{ DefaultSampler: sdktrace.AlwaysSample(), @@ -135,15 +135,21 @@ func TestUnaryClientInterceptor(t *testing.T) { for _, check := range checks { err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker) if err != nil { - t.Fatalf("failed to run unary interceptor: %v", err) + t.Errorf("failed to run unary interceptor: %v", err) + continue } spanData, ok := exp.spanMap[check.name] - if !ok || len(spanData) == 0 { - t.Fatalf("no span data found for name < %s >", check.name) + if !ok { + t.Errorf("no span data found for name < %s >", check.name) + continue } - attrs := spanData[0].Attributes + attrs := spanData.Attributes + if len(check.expectedAttr) > len(attrs) { + t.Errorf("attributes received are less than expected attributes, received %d, expected %d", + len(attrs), len(check.expectedAttr)) + } for _, attr := range attrs { expectedAttr, ok := check.expectedAttr[attr.Key] if ok { @@ -162,7 +168,11 @@ func TestUnaryClientInterceptor(t *testing.T) { } } - events := spanData[0].MessageEvents + events := spanData.MessageEvents + if len(check.eventsAttr) > len(events) { + t.Errorf("events received are less than expected events, received %d, expected %d", + len(events), len(check.eventsAttr)) + } for event := 0; event < len(check.eventsAttr); event++ { for _, attr := range events[event].Attributes { expectedAttr, ok := check.eventsAttr[event][attr.Key] @@ -196,7 +206,7 @@ func (mockClientStream) Header() (metadata.MD, error) { return nil, nil } func (mockClientStream) Trailer() metadata.MD { return nil } func TestStreamClientInterceptor(t *testing.T) { - exp := &testExporter{spanMap: make(map[string][]*export.SpanData)} + exp := &testExporter{spanMap: make(map[string]*export.SpanData)} tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp), sdktrace.WithConfig(sdktrace.Config{ DefaultSampler: sdktrace.AlwaysSample(), @@ -251,7 +261,7 @@ func TestStreamClientInterceptor(t *testing.T) { _ = streamClient.RecvMsg(reply) // added retry because span end is called in separate go routine - var spanData []*export.SpanData + var spanData *export.SpanData for retry := 0; retry < 5; retry++ { ok := false exp.mu.Lock() @@ -262,11 +272,11 @@ func TestStreamClientInterceptor(t *testing.T) { } time.Sleep(time.Second * 1) } - if len(spanData) == 0 { + if spanData == nil { t.Fatalf("no span data found for name < %s >", methodName) } - attrs := spanData[0].Attributes + attrs := spanData.Attributes expectedAttr := map[core.Key]string{ rpcServiceKey: "serviceName", netPeerIPKey: "fake", @@ -283,7 +293,7 @@ func TestStreamClientInterceptor(t *testing.T) { } } - events := spanData[0].MessageEvents + events := spanData.MessageEvents if len(events) != 20 { t.Fatalf("incorrect number of events expected 20 got %d", len(events)) } From 55905e58c5eb5f2e7cf56f7ba3aaec666569fb6e Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Fri, 15 May 2020 18:16:38 +0200 Subject: [PATCH 05/21] Remove krnowak from approvers --- CODEOWNERS | 2 +- CONTRIBUTING.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 9797c512b..868eb2405 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -12,6 +12,6 @@ # https://help.github.com/en/articles/about-code-owners # -* @jmacd @paivagustavo @krnowak @lizthegrey @MrAlias @Aneurysm9 @evantorrie +* @jmacd @paivagustavo @lizthegrey @MrAlias @Aneurysm9 @evantorrie CODEOWNERS @MrAlias @jmacd diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2e59e639..67a2e08bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -139,7 +139,6 @@ https://github.com/open-telemetry/opentelemetry-specification/issues/165 Approvers: -- [Krzesimir Nowak](https://github.com/krnowak), Kinvolk - [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb - [Gustavo Silva Paiva](https://github.com/paivagustavo), Stilingue - [Anthony Mirabella](https://github.com/Aneurysm9), Centene From 80a59c227540984bc8ac80fd134311a8c38fa86b Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 09:33:06 -0700 Subject: [PATCH 06/21] Update correlation context header name --- api/correlation/correlation_context_propagator.go | 4 +++- .../correlation_context_propagator_test.go | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/api/correlation/correlation_context_propagator.go b/api/correlation/correlation_context_propagator.go index 20e1cd6af..172a3b902 100644 --- a/api/correlation/correlation_context_propagator.go +++ b/api/correlation/correlation_context_propagator.go @@ -23,7 +23,9 @@ import ( "go.opentelemetry.io/otel/api/propagation" ) -const correlationContextHeader = "Correlation-Context" +// Temporary header name until W3C finalizes format. +// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name +const correlationContextHeader = "otcorrelations" // CorrelationContext propagates Key:Values in W3C CorrelationContext // format. diff --git a/api/correlation/correlation_context_propagator_test.go b/api/correlation/correlation_context_propagator_test.go index 3fe832fa6..5a88133eb 100644 --- a/api/correlation/correlation_context_propagator_test.go +++ b/api/correlation/correlation_context_propagator_test.go @@ -89,7 +89,7 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req, _ := http.NewRequest("GET", "http://example.com", nil) - req.Header.Set("Correlation-Context", tt.header) + req.Header.Set("otcorrelations", tt.header) ctx := context.Background() ctx = propagation.ExtractHTTP(ctx, props, req.Header) @@ -133,7 +133,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { req, _ := http.NewRequest("GET", "http://example.com", nil) - req.Header.Set("Correlation-Context", tt.header) + req.Header.Set("otcorrelations", tt.header) ctx := context.Background() ctx = propagation.ExtractHTTP(ctx, props, req.Header) @@ -202,17 +202,17 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) { ctx := correlation.ContextWithMap(context.Background(), correlation.NewMap(correlation.MapUpdate{MultiKV: tt.kvs})) propagation.InjectHTTP(ctx, props, req.Header) - gotHeader := req.Header.Get("Correlation-Context") + gotHeader := req.Header.Get("otcorrelations") wantedLen := len(strings.Join(tt.wantInHeader, ",")) if wantedLen != len(gotHeader) { t.Errorf( - "%s: Inject Correlation-Context incorrect length %d != %d.", tt.name, tt.wantedLen, len(gotHeader), + "%s: Inject otcorrelations incorrect length %d != %d.", tt.name, tt.wantedLen, len(gotHeader), ) } for _, inHeader := range tt.wantInHeader { if !strings.Contains(gotHeader, inHeader) { t.Errorf( - "%s: Inject Correlation-Context missing part of header: %s in %s", tt.name, inHeader, gotHeader, + "%s: Inject otcorrelations missing part of header: %s in %s", tt.name, inHeader, gotHeader, ) } } @@ -222,7 +222,7 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) { func TestTraceContextPropagator_GetAllKeys(t *testing.T) { var propagator correlation.CorrelationContext - want := []string{"Correlation-Context"} + want := []string{"otcorrelations"} got := propagator.GetAllKeys() if diff := cmp.Diff(got, want); diff != "" { t.Errorf("GetAllKeys: -got +want %s", diff) From 7c209b5c8c14b4d837060962fa10cdf335b69d29 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 11:32:03 -0700 Subject: [PATCH 07/21] Rename resourcekeys to singular resourcekey --- sdk/resource/{resourcekeys => resourcekey}/const.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename sdk/resource/{resourcekeys => resourcekey}/const.go (93%) diff --git a/sdk/resource/resourcekeys/const.go b/sdk/resource/resourcekey/const.go similarity index 93% rename from sdk/resource/resourcekeys/const.go rename to sdk/resource/resourcekey/const.go index 5adc993dd..ad266d165 100644 --- a/sdk/resource/resourcekeys/const.go +++ b/sdk/resource/resourcekey/const.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package resourcekeys contains well known type and label keys for resources. -package resourcekeys // import "go.opentelemetry.io/otel/sdk/resource/resourcekeys" +// Package resourcekey contains well known type and label keys for resources. +package resourcekey // import "go.opentelemetry.io/otel/sdk/resource/resourcekey" // Constants for Service resources. const ( From 4eecaf53912e3695d13f98ea1620fe12d7e32082 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 11:35:44 -0700 Subject: [PATCH 08/21] Update resourcekey package doc --- sdk/resource/resourcekey/const.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdk/resource/resourcekey/const.go b/sdk/resource/resourcekey/const.go index ad266d165..08769e233 100644 --- a/sdk/resource/resourcekey/const.go +++ b/sdk/resource/resourcekey/const.go @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package resourcekey contains well known type and label keys for resources. +// Package resourcekey contains standard resource attribute keys as defined +// by the OpenTelemetry specification +// (https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/resource/semantic_conventions). package resourcekey // import "go.opentelemetry.io/otel/sdk/resource/resourcekey" // Constants for Service resources. From f7f3fc39181f6326752f0b889774010d02e08a85 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 11:38:02 -0700 Subject: [PATCH 09/21] Remove redundant "Key" from const names --- sdk/resource/resourcekey/const.go | 50 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/sdk/resource/resourcekey/const.go b/sdk/resource/resourcekey/const.go index 08769e233..b2ca3b6cf 100644 --- a/sdk/resource/resourcekey/const.go +++ b/sdk/resource/resourcekey/const.go @@ -20,18 +20,18 @@ package resourcekey // import "go.opentelemetry.io/otel/sdk/resource/resourcekey // Constants for Service resources. const ( // A uniquely identifying name for a Service. - ServiceKeyName = "service.name" - ServiceKeyNamespace = "service.namespace" - ServiceKeyInstanceID = "service.instance.id" - ServiceKeyVersion = "service.version" + ServiceName = "service.name" + ServiceNamespace = "service.namespace" + ServiceInstanceID = "service.instance.id" + ServiceVersion = "service.version" ) // Constants for Library resources. const ( // A uniquely identifying name for a Library. - LibraryKeyName = "library.name" - LibraryKeyLanguage = "library.language" - LibraryKeyVersion = "library.version" + LibraryName = "library.name" + LibraryLanguage = "library.language" + LibraryVersion = "library.version" ) // Constants for Kubernetes resources. @@ -40,26 +40,26 @@ const ( // does not have cluster names as an internal concept so this may be // set to any meaningful value within the environment. For example, // GKE clusters have a name which can be used for this label. - K8SKeyClusterName = "k8s.cluster.name" - K8SKeyNamespaceName = "k8s.namespace.name" - K8SKeyPodName = "k8s.pod.name" - K8SKeyDeploymentName = "k8s.deployment.name" + K8SClusterName = "k8s.cluster.name" + K8SNamespaceName = "k8s.namespace.name" + K8SPodName = "k8s.pod.name" + K8SDeploymentName = "k8s.deployment.name" ) // Constants for Container resources. const ( // A uniquely identifying name for the Container. - ContainerKeyName = "container.name" - ContainerKeyImageName = "container.image.name" - ContainerKeyImageTag = "container.image.tag" + ContainerName = "container.name" + ContainerImageName = "container.image.name" + ContainerImageTag = "container.image.tag" ) // Constants for Cloud resources. const ( - CloudKeyProvider = "cloud.provider" - CloudKeyAccountID = "cloud.account.id" - CloudKeyRegion = "cloud.region" - CloudKeyZone = "cloud.zone" + CloudProvider = "cloud.provider" + CloudAccountID = "cloud.account.id" + CloudRegion = "cloud.region" + CloudZone = "cloud.zone" // Cloud Providers CloudProviderAWS = "aws" @@ -70,13 +70,13 @@ const ( // Constants for Host resources. const ( // A uniquely identifying name for the host. - HostKeyName = "host.name" + HostName = "host.name" // A hostname as returned by the 'hostname' command on host machine. - HostKeyHostName = "host.hostname" - HostKeyID = "host.id" - HostKeyType = "host.type" - HostKeyImageName = "host.image.name" - HostKeyImageID = "host.image.id" - HostKeyImageVersion = "host.image.version" + HostHostName = "host.hostname" + HostID = "host.id" + HostType = "host.type" + HostImageName = "host.image.name" + HostImageID = "host.image.id" + HostImageVersion = "host.image.version" ) From 55bbf514599c0f1830481cd58c0b8672054d1dc9 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 11:44:17 -0700 Subject: [PATCH 10/21] Switch to kv.Key types --- sdk/resource/resourcekey/const.go | 57 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/sdk/resource/resourcekey/const.go b/sdk/resource/resourcekey/const.go index b2ca3b6cf..3c5e1d8a5 100644 --- a/sdk/resource/resourcekey/const.go +++ b/sdk/resource/resourcekey/const.go @@ -17,21 +17,23 @@ // (https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/resource/semantic_conventions). package resourcekey // import "go.opentelemetry.io/otel/sdk/resource/resourcekey" +import "go.opentelemetry.io/otel/api/kv" + // Constants for Service resources. const ( // A uniquely identifying name for a Service. - ServiceName = "service.name" - ServiceNamespace = "service.namespace" - ServiceInstanceID = "service.instance.id" - ServiceVersion = "service.version" + ServiceName = kv.Key("service.name") + ServiceNamespace = kv.Key("service.namespace") + ServiceInstanceID = kv.Key("service.instance.id") + ServiceVersion = kv.Key("service.version") ) // Constants for Library resources. const ( // A uniquely identifying name for a Library. - LibraryName = "library.name" - LibraryLanguage = "library.language" - LibraryVersion = "library.version" + LibraryName = kv.Key("library.name") + LibraryLanguage = kv.Key("library.language") + LibraryVersion = kv.Key("library.version") ) // Constants for Kubernetes resources. @@ -40,43 +42,38 @@ const ( // does not have cluster names as an internal concept so this may be // set to any meaningful value within the environment. For example, // GKE clusters have a name which can be used for this label. - K8SClusterName = "k8s.cluster.name" - K8SNamespaceName = "k8s.namespace.name" - K8SPodName = "k8s.pod.name" - K8SDeploymentName = "k8s.deployment.name" + K8SClusterName = kv.Key("k8s.cluster.name") + K8SNamespaceName = kv.Key("k8s.namespace.name") + K8SPodName = kv.Key("k8s.pod.name") + K8SDeploymentName = kv.Key("k8s.deployment.name") ) // Constants for Container resources. const ( // A uniquely identifying name for the Container. - ContainerName = "container.name" - ContainerImageName = "container.image.name" - ContainerImageTag = "container.image.tag" + ContainerName = kv.Key("container.name") + ContainerImageName = kv.Key("container.image.name") + ContainerImageTag = kv.Key("container.image.tag") ) // Constants for Cloud resources. const ( - CloudProvider = "cloud.provider" - CloudAccountID = "cloud.account.id" - CloudRegion = "cloud.region" - CloudZone = "cloud.zone" - - // Cloud Providers - CloudProviderAWS = "aws" - CloudProviderGCP = "gcp" - CloudProviderAZURE = "azure" + CloudProvider = kv.Key("cloud.provider") + CloudAccountID = kv.Key("cloud.account.id") + CloudRegion = kv.Key("cloud.region") + CloudZone = kv.Key("cloud.zone") ) // Constants for Host resources. const ( // A uniquely identifying name for the host. - HostName = "host.name" + HostName = kv.Key("host.name") // A hostname as returned by the 'hostname' command on host machine. - HostHostName = "host.hostname" - HostID = "host.id" - HostType = "host.type" - HostImageName = "host.image.name" - HostImageID = "host.image.id" - HostImageVersion = "host.image.version" + HostHostName = kv.Key("host.hostname") + HostID = kv.Key("host.id") + HostType = kv.Key("host.type") + HostImageName = kv.Key("host.image.name") + HostImageID = kv.Key("host.image.id") + HostImageVersion = kv.Key("host.image.version") ) From 1d554f34c1e8335393cea231578c3d45acddb29f Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 12:42:13 -0700 Subject: [PATCH 11/21] Add standard package contain all semantic conventions --- sdk/resource/resourcekey/const.go => api/standard/resource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename sdk/resource/resourcekey/const.go => api/standard/resource.go (94%) diff --git a/sdk/resource/resourcekey/const.go b/api/standard/resource.go similarity index 94% rename from sdk/resource/resourcekey/const.go rename to api/standard/resource.go index 3c5e1d8a5..83a8b2160 100644 --- a/sdk/resource/resourcekey/const.go +++ b/api/standard/resource.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package resourcekey contains standard resource attribute keys as defined +// Package standard contains standard resource attribute keys as defined // by the OpenTelemetry specification // (https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/resource/semantic_conventions). -package resourcekey // import "go.opentelemetry.io/otel/sdk/resource/resourcekey" +package standard // import "go.opentelemetry.io/otel/api/standard" import "go.opentelemetry.io/otel/api/kv" From 721628d402629d47610a5acb97c495e618a82edc Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 12:46:53 -0700 Subject: [PATCH 12/21] Update standard package docs --- api/standard/doc.go | 22 ++++++++++++++++++++++ api/standard/resource.go | 3 --- 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 api/standard/doc.go diff --git a/api/standard/doc.go b/api/standard/doc.go new file mode 100644 index 000000000..b681eccf8 --- /dev/null +++ b/api/standard/doc.go @@ -0,0 +1,22 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package standard contains keys and values that have been standardized for +// use in OpenTelemetry. These standardizations are specified in the +// OpenTelemetry specification: +// +// - https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/resource/semantic_conventions +// - https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/trace/semantic_conventions +// - https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/metrics/semantic_conventions +package standard diff --git a/api/standard/resource.go b/api/standard/resource.go index 83a8b2160..082827457 100644 --- a/api/standard/resource.go +++ b/api/standard/resource.go @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package standard contains standard resource attribute keys as defined -// by the OpenTelemetry specification -// (https://github.com/open-telemetry/opentelemetry-specification/tree/v0.4.0/specification/resource/semantic_conventions). package standard // import "go.opentelemetry.io/otel/api/standard" import "go.opentelemetry.io/otel/api/kv" From 5c160d31e58502ee6b914be677738e946d86a342 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 13:21:52 -0700 Subject: [PATCH 13/21] Update to v0.4.0 specification Change `library.*` to `telemetry.sdk.*`. Add FaaS. Add comments to all constants. --- api/standard/resource.go | 156 +++++++++++++++++++++++++++++---------- 1 file changed, 116 insertions(+), 40 deletions(-) diff --git a/api/standard/resource.go b/api/standard/resource.go index 082827457..5bb6beb2d 100644 --- a/api/standard/resource.go +++ b/api/standard/resource.go @@ -16,61 +16,137 @@ package standard // import "go.opentelemetry.io/otel/api/standard" import "go.opentelemetry.io/otel/api/kv" -// Constants for Service resources. +// Standard service resource attribute keys. const ( - // A uniquely identifying name for a Service. - ServiceName = kv.Key("service.name") - ServiceNamespace = kv.Key("service.namespace") - ServiceInstanceID = kv.Key("service.instance.id") - ServiceVersion = kv.Key("service.version") + // Name of the service. + ServiceNameKey = kv.Key("service.name") + + // A namespace for `service.name`. This needs to have meaning that helps + // to distinguish a group of services. For example, the team name that + // owns a group of services. `service.name` is expected to be unique + // within the same namespace. + ServiceNamespaceKey = kv.Key("service.namespace") + + // A unique identifier of the service instance. In conjunction with the + // `service.name` and `service.namespace` this must be unique. + ServiceInstanceIDKey = kv.Key("service.instance.id") + + // The version of the service API. + ServiceVersionKey = kv.Key("service.version") ) -// Constants for Library resources. +// Standard telemetry SDK resource attribute keys. const ( - // A uniquely identifying name for a Library. - LibraryName = kv.Key("library.name") - LibraryLanguage = kv.Key("library.language") - LibraryVersion = kv.Key("library.version") + // The name of the telemetry SDK. + // + // The default OpenTelemetry SDK provided by the OpenTelemetry project + // MUST set telemetry.sdk.name to the value `opentelemetry`. + // + // If another SDK is used, this attribute MUST be set to the import path + // of that SDK's package. + // + // The value `opentelemetry` is reserved and MUST NOT be used by + // non-OpenTelemetry SDKs. + TelemetrySDKNameKey = kv.Key("telemetry.sdk.name") + + // The language of the telemetry SDK. + TelemetrySDKLanguageKey = kv.Key("telemetry.sdk.language") + + // The version string of the telemetry SDK. + TelemetrySDKVersionKey = kv.Key("telemetry.sdk.version") ) -// Constants for Kubernetes resources. +// Standard telemetry SDK resource attributes. +var ( + TelemetrySDKLanguageGo = TelemetrySDKLanguageKey.String("go") +) + +// Standard container resource attribute keys. +const ( + // A uniquely identifying name for the Container. + ContainerNameKey = kv.Key("container.name") + + // Name of the image the container was built on. + ContainerImageNameKey = kv.Key("container.image.name") + + // Container image tag. + ContainerImageTagKey = kv.Key("container.image.tag") +) + +// Standard Function-as-a-Service resource attribute keys. +const ( + // A uniquely identifying name for the FaaS. + FaaSName = kv.Key("faas.name") + + // The unique name of the function being executed. + FaaSID = kv.Key("faas.id") + + // The version of the function being executed. + FaaSVersion = kv.Key("faas.version") + + // The execution environment identifier. + FaaSInstance = kv.Key("faas.instance") +) + +// Standard Kubernetes resource attribute keys. const ( // A uniquely identifying name for the Kubernetes cluster. Kubernetes // does not have cluster names as an internal concept so this may be // set to any meaningful value within the environment. For example, // GKE clusters have a name which can be used for this label. - K8SClusterName = kv.Key("k8s.cluster.name") - K8SNamespaceName = kv.Key("k8s.namespace.name") - K8SPodName = kv.Key("k8s.pod.name") - K8SDeploymentName = kv.Key("k8s.deployment.name") + K8SClusterNameKey = kv.Key("k8s.cluster.name") + + // The name of the namespace that the pod is running in. + K8SNamespaceNameKey = kv.Key("k8s.namespace.name") + + // The name of the pod. + K8SPodNameKey = kv.Key("k8s.pod.name") + + // The name of the deployment. + K8SDeploymentNameKey = kv.Key("k8s.deployment.name") ) -// Constants for Container resources. -const ( - // A uniquely identifying name for the Container. - ContainerName = kv.Key("container.name") - ContainerImageName = kv.Key("container.image.name") - ContainerImageTag = kv.Key("container.image.tag") -) - -// Constants for Cloud resources. -const ( - CloudProvider = kv.Key("cloud.provider") - CloudAccountID = kv.Key("cloud.account.id") - CloudRegion = kv.Key("cloud.region") - CloudZone = kv.Key("cloud.zone") -) - -// Constants for Host resources. +// Standard host resource attribute keys. const ( // A uniquely identifying name for the host. - HostName = kv.Key("host.name") + HostNameKey = kv.Key("host.name") // A hostname as returned by the 'hostname' command on host machine. - HostHostName = kv.Key("host.hostname") - HostID = kv.Key("host.id") - HostType = kv.Key("host.type") - HostImageName = kv.Key("host.image.name") - HostImageID = kv.Key("host.image.id") - HostImageVersion = kv.Key("host.image.version") + HostHostNameKey = kv.Key("host.hostname") + + // Unique host ID. For cloud environments this will be the instance ID. + HostIDKey = kv.Key("host.id") + + // Type of host. For cloud environments this will be the machine type. + HostTypeKey = kv.Key("host.type") + + // Name of the OS or VM image the host is running. + HostImageNameKey = kv.Key("host.image.name") + + // Identifier of the image the host is running. + HostImageIDKey = kv.Key("host.image.id") + + // Version of the image the host is running. + HostImageVersionKey = kv.Key("host.image.version") +) + +// Standard cloud environment resource attribute keys. +const ( + // Name of the cloud provider. + CloudProviderKey = kv.Key("cloud.provider") + + // The account ID from the cloud provider used for authorization. + CloudAccountIDKey = kv.Key("cloud.account.id") + + // Geographical region where this resource is. + CloudRegionKey = kv.Key("cloud.region") + + // Zone of the region where this resource is. + CloudZoneKey = kv.Key("cloud.zone") +) + +var ( + CloudProviderAWS = CloudProviderKey.String("aws") + CloudProviderAzure = CloudProviderKey.String("azure") + CloudProviderGCP = CloudProviderKey.String("gcp") ) From f4a25cf745a6d9fc24f5e9fdd8f47c80b03c4464 Mon Sep 17 00:00:00 2001 From: Ahmed Mujtaba Date: Fri, 15 May 2020 22:43:07 +0200 Subject: [PATCH 14/21] Added condition for missing attr received in attr expected --- plugin/grpctrace/interceptor_test.go | 89 +++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/plugin/grpctrace/interceptor_test.go b/plugin/grpctrace/interceptor_test.go index 3667b9dbe..243bf776a 100644 --- a/plugin/grpctrace/interceptor_test.go +++ b/plugin/grpctrace/interceptor_test.go @@ -19,6 +19,7 @@ import ( "testing" "time" + "github.com/golang/protobuf/proto" "google.golang.org/grpc" "google.golang.org/grpc/metadata" @@ -93,42 +94,96 @@ func TestUnaryClientInterceptor(t *testing.T) { }, eventsAttr: []map[core.Key]core.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), }, }, }, { name: "/serviceName/bar", expectedAttr: map[core.Key]core.Value{ - rpcServiceKey: core.String("serviceName"), + rpcServiceKey: core.String("serviceName"), + netPeerIPKey: core.String("fake"), + netPeerPortKey: core.String("connection"), }, eventsAttr: []map[core.Key]core.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), }, }, }, { - name: "serviceName/bar", - expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName")}, + name: "serviceName/bar", + expectedAttr: map[core.Key]core.Value{ + rpcServiceKey: core.String("serviceName"), + netPeerIPKey: core.String("fake"), + netPeerPortKey: core.String("connection"), + }, + eventsAttr: []map[core.Key]core.Value{ + { + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + }, + { + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + }, + }, }, { - name: "invalidName", - expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("")}, + name: "invalidName", + expectedAttr: map[core.Key]core.Value{ + rpcServiceKey: core.String(""), + netPeerIPKey: core.String("fake"), + netPeerPortKey: core.String("connection"), + }, + eventsAttr: []map[core.Key]core.Value{ + { + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + }, + { + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + }, + }, }, { - name: "/github.com.foo.serviceName_123/method", - expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName_123")}, + name: "/github.com.foo.serviceName_123/method", + expectedAttr: map[core.Key]core.Value{ + rpcServiceKey: core.String("serviceName_123"), + netPeerIPKey: core.String("fake"), + netPeerPortKey: core.String("connection"), + }, + eventsAttr: []map[core.Key]core.Value{ + { + messageTypeKey: core.String("SENT"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + }, + { + messageTypeKey: core.String("RECEIVED"), + messageIDKey: core.Int(1), + messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + }, + }, }, } @@ -158,6 +213,8 @@ func TestUnaryClientInterceptor(t *testing.T) { expectedAttr.AsString(), attr.Value.AsString()) } delete(check.expectedAttr, attr.Key) + } else { + t.Errorf("attribute %s not found in expected attributes map", string(attr.Key)) } } @@ -182,6 +239,8 @@ func TestUnaryClientInterceptor(t *testing.T) { string(attr.Key), attr.Value.AsString(), expectedAttr.AsString()) } delete(check.eventsAttr[event], attr.Key) + } else { + t.Errorf("attribute in event %s not found in expected attributes map", string(attr.Key)) } } if len(check.eventsAttr[event]) > 0 { From 5abfeb02a98a233509e813f49ccd0c26cd219308 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 15:20:30 -0700 Subject: [PATCH 15/21] Add tracing standards --- api/standard/trace.go | 262 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 api/standard/trace.go diff --git a/api/standard/trace.go b/api/standard/trace.go new file mode 100644 index 000000000..b3e2f4b8b --- /dev/null +++ b/api/standard/trace.go @@ -0,0 +1,262 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package standard + +import "go.opentelemetry.io/otel/api/kv" + +// Standard attribute keys used for network related operations. +const ( + // Transport protocol used. + NetTransportKey = kv.Key("net.transport") + + // Remote address of the peer. + NetPeerIPKey = kv.Key("net.peer.ip") + + // Remote port number. + NetPeerPortKey = kv.Key("net.peer.port") + + // Remote hostname or similar. + NetPeerNameKey = kv.Key("net.peer.name") + + // Local host IP. Useful in case of a multi-IP host. + NetHostIPKey = kv.Key("net.host.ip") + + // Local host port. + NetHostPortKey = kv.Key("net.host.port") + + // Local hostname or similar. + NetHostNameKey = kv.Key("net.host.name") +) + +var ( + NetTransportTCP = NetTransportKey.String("IP.TCP") + NetTransportUDP = NetTransportKey.String("IP.UDP") + NetTransportIP = NetTransportKey.String("IP") + NetTransportUnix = NetTransportKey.String("Unix") + NetTransportPipe = NetTransportKey.String("pipe") + NetTransportInProc = NetTransportKey.String("inproc") + NetTransportOther = NetTransportKey.String("other") +) + +// Standard attribute keys used to identify an authorized enduser. +const ( + // Username or the client identifier extracted from the access token or + // authorization header in the inbound request from outside the system. + EnduserIDKey = kv.Key("enduser.id") + + // Actual or assumed role the client is making the request with. + EnduserRoleKey = kv.Key("enduser.role") + + // Scopes or granted authorities the client currently possesses. + EnduserScopeKey = kv.Key("enduser.scope") +) + +// Standard attribute keys for HTTP. +const ( + // HTTP request method. + HTTPMethodKey = kv.Key("http.method") + + // Full HTTP request URL in the form: + // scheme://host[:port]/path?query[#fragment]. + HTTPUrlKey = kv.Key("http.url") + + // The full request target as passed in a HTTP request line or + // equivalent, e.g. "/path/12314/?q=ddds#123". + HTTPTargetKey = kv.Key("http.target") + + // The value of the HTTP host header. + HTTPHostKey = kv.Key("http.host") + + // The URI scheme identifying the used protocol. + HTTPSchemeKey = kv.Key("http.scheme") + + // HTTP response status code. + HTTPStatusCodeKey = kv.Key("http.status_code") + + // HTTP reason phrase. + HTTPStatusTextKey = kv.Key("http.status_text") + + // Kind of HTTP protocol used. + HTTPFlavorKey = kv.Key("http.flavor") + + // Value of the HTTP User-Agent header sent by the client. + HTTPUserAgentKey = kv.Key("http.user_agent") + + // The primary server name of the matched virtual host. + HTTPServerNameKey = kv.Key("http.server_name") + + // The matched route served (path template). For example, + // "/users/:userID?". + HTTPRouteKey = kv.Key("http.route") + + // The IP address of the original client behind all proxies, if known + // (e.g. from X-Forwarded-For). + HTTPClientIPKey = kv.Key("http.client_ip") +) + +var ( + HTTPSchemeHTTP = HTTPSchemeKey.String("http") + HTTPSchemeHTTPS = HTTPSchemeKey.String("https") + + HTTPFlavor1_0 = HTTPFlavorKey.String("1.0") + HTTPFlavor1_1 = HTTPFlavorKey.String("1.1") + HTTPFlavor2 = HTTPFlavorKey.String("2") + HTTPFlavorSPDY = HTTPFlavorKey.String("SPDY") + HTTPFlavorQUIC = HTTPFlavorKey.String("QUIC") +) + +// Standard attribute keys for database clients. +const ( + // Database type. For any SQL database, "sql". For others, the + // lower-case database category, e.g. "cassandra", "hbase", or "redis". + DBTypeKey = kv.Key("db.type") + + // Database instance name. + DBInstanceKey = kv.Key("db.instance") + + // A database statement for the given database type. + DBStatementKey = kv.Key("db.statement") + + // Username for accessing database. + DBUserKey = kv.Key("db.user") + + // Database URL. + DBUrlKey = kv.Key("db.url") +) + +// Standard attribute keys for RPC. +const ( + // The RPC service name. + RPCServiceKey = kv.Key("rpc.service") + + // Name of message transmitted or received. + RPCNameKey = kv.Key("name") + + // Type of message transmitted or received. + RPCMessageTypeKey = kv.Key("message.type") + + // Identifier of message transmitted or received. + RPCMessageIDKey = kv.Key("message.id") + + // The compressed size of the message transmitted or received in bytes. + RPCMessageCompressedSizeKey = kv.Key("message.compressed_size") + + // The uncompressed size of the message transmitted or received in + // bytes. + RPCMessageUncompressedSizeKey = kv.Key("message.uncompressed_size") +) + +var ( + RPCNameMessage = RPCNameKey.String("message") + + RPCMessageTypeSent = RPCMessageTypeKey.String("SENT") + RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED") +) + +// Standard attribute keys for messaging systems. +const ( + // A unique identifier describing the messaging system. For example, + // kafka, rabbitmq or activemq. + MessagingSystemKey = kv.Key("messaging.system") + + // The message destination name, e.g. MyQueue or MyTopic. + MessagingDestinationKey = kv.Key("messaging.destination") + + // The kind of message destination. + MessagingDestinationKindKey = kv.Key("messaging.destination_kind") + + // Describes if the destination is temporary or not. + MessagingTempDestinationKey = kv.Key("messaging.temp_destination") + + // The name of the transport protocol. + MessagingProtocolKey = kv.Key("messaging.protocol") + + // The version of the transport protocol. + MessagingProtocolVersionKey = kv.Key("messaging.protocol_version") + + // Messaging service URL. + MessagingURLKey = kv.Key("messaging.url") + + // Identifier used by the messaging system for a message. + MessagingMessageIDKey = kv.Key("messaging.message_id") + + // Identifier used by the messaging system for a conversation. + MessagingConversationIDKey = kv.Key("messaging.conversation_id") + + // The (uncompressed) size of the message payload in bytes. + MessagingMessagePayloadSizeBytesKey = kv.Key("messaging.message_payload_size_bytes") + + // The compressed size of the message payload in bytes. + MessagingMessagePayloadCompressedSizeBytesKey = kv.Key("messaging.message_payload_compressed_size_bytes") + + // Identifies which part and kind of message consumption is being + // preformed. + MessagingOperationKey = kv.Key("messaging.operation") + + // RabbitMQ specific attribute describing the destination routing key. + MessagingRabbitMQRoutingKeyKey = kv.Key("messaging.rabbitmq.routing_key") +) + +var ( + MessagingDestinationKindKeyQueue = MessagingDestinationKindKey.String("queue") + MessagingDestinationKindKeyTopic = MessagingDestinationKindKey.String("topic") + + MessagingTempDestination = MessagingTempDestinationKey.Bool(true) + + MessagingOperationReceive = MessagingOperationKey.String("receive") + MessagingOperationProcess = MessagingOperationKey.String("process") +) + +// Standard attribute keys for FaaS systems. +const ( + + // Type of the trigger on which the function is executed. + FaaSTriggerKey = kv.Key("faas.trigger") + + // String containing the execution identifier of the function. + FaaSExecutionKey = kv.Key("faas.execution") + + // The name of the source on which the operation was performed. + // For example, in Cloud Storage or S3 corresponds to the bucket name, + // and in Cosmos DB to the database name. + FaaSDocumentCollectionKey = kv.Key("faas.document.collection") + + // The type of the operation that was performed on the data. + FaaSDocumentOperationKey = kv.Key("faas.document.operation") + + // A string containing the time when the data was accessed. + FaaSDocumentTimeKey = kv.Key("faas.document.time") + + // The document name/table subjected to the operation. + FaaSDocumentNameKey = kv.Key("faas.document.name") + + // The function invocation time. + FaaSTimeKey = kv.Key("faas.time") + + // The schedule period as Cron Expression. + FaaSCronKey = kv.Key("faas.cron") +) + +var ( + FaasTriggerDatasource = FaaSTriggerKey.String("datasource") + FaasTriggerHTTP = FaaSTriggerKey.String("http") + FaasTriggerPubSub = FaaSTriggerKey.String("pubsub") + FaasTriggerTimer = FaaSTriggerKey.String("timer") + FaasTriggerOther = FaaSTriggerKey.String("other") + + FaaSDocumentOperationInsert = FaaSDocumentOperationKey.String("insert") + FaaSDocumentOperationEdit = FaaSDocumentOperationKey.String("edit") + FaaSDocumentOperationDelete = FaaSDocumentOperationKey.String("delete") +) From 55d4f7c31f38758446f5c1171dfa272c549a33d8 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Fri, 15 May 2020 16:27:40 -0700 Subject: [PATCH 16/21] Upgrade to v0.5.0 --- plugin/grpctrace/interceptor_test.go | 123 ++++++++++++++------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/plugin/grpctrace/interceptor_test.go b/plugin/grpctrace/interceptor_test.go index 243bf776a..a92c7177f 100644 --- a/plugin/grpctrace/interceptor_test.go +++ b/plugin/grpctrace/interceptor_test.go @@ -23,7 +23,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" - "go.opentelemetry.io/otel/api/core" + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/kv/value" export "go.opentelemetry.io/otel/sdk/export/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) @@ -82,106 +83,106 @@ func TestUnaryClientInterceptor(t *testing.T) { checks := []struct { name string - expectedAttr map[core.Key]core.Value - eventsAttr []map[core.Key]core.Value + expectedAttr map[kv.Key]value.Value + eventsAttr []map[kv.Key]value.Value }{ { name: "/github.com.serviceName/bar", - expectedAttr: map[core.Key]core.Value{ - rpcServiceKey: core.String("serviceName"), - netPeerIPKey: core.String("fake"), - netPeerPortKey: core.String("connection"), + expectedAttr: map[kv.Key]value.Value{ + rpcServiceKey: value.String("serviceName"), + netPeerIPKey: value.String("fake"), + netPeerPortKey: value.String("connection"), }, - eventsAttr: []map[core.Key]core.Value{ + eventsAttr: []map[kv.Key]value.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + messageTypeKey: value.String("SENT"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + messageTypeKey: value.String("RECEIVED"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))), }, }, }, { name: "/serviceName/bar", - expectedAttr: map[core.Key]core.Value{ - rpcServiceKey: core.String("serviceName"), - netPeerIPKey: core.String("fake"), - netPeerPortKey: core.String("connection"), + expectedAttr: map[kv.Key]value.Value{ + rpcServiceKey: value.String("serviceName"), + netPeerIPKey: value.String("fake"), + netPeerPortKey: value.String("connection"), }, - eventsAttr: []map[core.Key]core.Value{ + eventsAttr: []map[kv.Key]value.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + messageTypeKey: value.String("SENT"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + messageTypeKey: value.String("RECEIVED"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))), }, }, }, { name: "serviceName/bar", - expectedAttr: map[core.Key]core.Value{ - rpcServiceKey: core.String("serviceName"), - netPeerIPKey: core.String("fake"), - netPeerPortKey: core.String("connection"), + expectedAttr: map[kv.Key]value.Value{ + rpcServiceKey: value.String("serviceName"), + netPeerIPKey: value.String("fake"), + netPeerPortKey: value.String("connection"), }, - eventsAttr: []map[core.Key]core.Value{ + eventsAttr: []map[kv.Key]value.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + messageTypeKey: value.String("SENT"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + messageTypeKey: value.String("RECEIVED"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))), }, }, }, { name: "invalidName", - expectedAttr: map[core.Key]core.Value{ - rpcServiceKey: core.String(""), - netPeerIPKey: core.String("fake"), - netPeerPortKey: core.String("connection"), + expectedAttr: map[kv.Key]value.Value{ + rpcServiceKey: value.String(""), + netPeerIPKey: value.String("fake"), + netPeerPortKey: value.String("connection"), }, - eventsAttr: []map[core.Key]core.Value{ + eventsAttr: []map[kv.Key]value.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + messageTypeKey: value.String("SENT"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + messageTypeKey: value.String("RECEIVED"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))), }, }, }, { name: "/github.com.foo.serviceName_123/method", - expectedAttr: map[core.Key]core.Value{ - rpcServiceKey: core.String("serviceName_123"), - netPeerIPKey: core.String("fake"), - netPeerPortKey: core.String("connection"), + expectedAttr: map[kv.Key]value.Value{ + rpcServiceKey: value.String("serviceName_123"), + netPeerIPKey: value.String("fake"), + netPeerPortKey: value.String("connection"), }, - eventsAttr: []map[core.Key]core.Value{ + eventsAttr: []map[kv.Key]value.Value{ { - messageTypeKey: core.String("SENT"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(req))), + messageTypeKey: value.String("SENT"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(req))), }, { - messageTypeKey: core.String("RECEIVED"), - messageIDKey: core.Int(1), - messageUncompressedSizeKey: core.Int(proto.Size(proto.Message(reply))), + messageTypeKey: value.String("RECEIVED"), + messageIDKey: value.Int(1), + messageUncompressedSizeKey: value.Int(proto.Size(proto.Message(reply))), }, }, }, @@ -336,7 +337,7 @@ func TestStreamClientInterceptor(t *testing.T) { } attrs := spanData.Attributes - expectedAttr := map[core.Key]string{ + expectedAttr := map[kv.Key]string{ rpcServiceKey: "serviceName", netPeerIPKey: "fake", netPeerPortKey: "connection", @@ -358,12 +359,12 @@ func TestStreamClientInterceptor(t *testing.T) { } for i := 0; i < 20; i += 2 { msgID := i/2 + 1 - validate := func(eventName string, attrs []core.KeyValue) { + validate := func(eventName string, attrs []kv.KeyValue) { for _, attr := range attrs { if attr.Key == messageTypeKey && attr.Value.AsString() != eventName { t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, attr.Value.AsString()) } - if attr.Key == messageIDKey && attr.Value != core.Int(msgID) { + if attr.Key == messageIDKey && attr.Value != value.Int(msgID) { t.Errorf("invalid id for message event expected %d received %d", msgID, attr.Value.AsInt32()) } } From 0122b586b7759042ba1f8d8e0efe2319824ec311 Mon Sep 17 00:00:00 2001 From: ET Date: Fri, 15 May 2020 21:53:05 -0700 Subject: [PATCH 17/21] Ensure golang alpine image is running golang-1.14 (#733) Older versions of go (even only as recently as 1.12.7) have problems building outside of $GOPATH --- example/http/Dockerfile | 2 +- example/zipkin/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/http/Dockerfile b/example/http/Dockerfile index 01493194c..23f88befd 100644 --- a/example/http/Dockerfile +++ b/example/http/Dockerfile @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:alpine AS base +FROM golang:1.14-alpine AS base COPY . /go/src/github.com/open-telemetry/opentelemetry-go/ WORKDIR /go/src/github.com/open-telemetry/opentelemetry-go/example/http/ diff --git a/example/zipkin/Dockerfile b/example/zipkin/Dockerfile index 6efef34b5..46421442b 100644 --- a/example/zipkin/Dockerfile +++ b/example/zipkin/Dockerfile @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:alpine +FROM golang:1.14-alpine COPY . /go/src/github.com/open-telemetry/opentelemetry-go/ WORKDIR /go/src/github.com/open-telemetry/opentelemetry-go/example/zipkin/ RUN go install ./main.go From 6bc14ffd2ccc1f3090c8a58f0eb9143245576f06 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Fri, 15 May 2020 22:11:12 -0700 Subject: [PATCH 18/21] Replace Measure instrument by ValueRecorder instrument (#732) * Measure->Value recorder and cleanups re: measure * More edits * More edits * Feedback --- api/global/internal/benchmark_test.go | 2 +- api/global/internal/meter_test.go | 22 +++--- api/global/internal/registry_test.go | 8 +- api/metric/api_test.go | 14 ++-- api/metric/doc.go | 70 ++++++---------- api/metric/kind.go | 4 +- api/metric/kind_string.go | 6 +- api/metric/meter.go | 16 ++-- api/metric/must.go | 12 +-- api/metric/registry/registry_test.go | 8 +- api/metric/sdkapi.go | 2 +- api/metric/sync.go | 12 +-- api/metric/{measure.go => valuerecorder.go} | 48 +++++------ example/basic/main.go | 10 +-- example/prometheus/main.go | 18 ++--- exporters/metric/prometheus/prometheus.go | 4 +- .../metric/prometheus/prometheus_test.go | 74 ++++++++--------- exporters/metric/stdout/stdout.go | 6 +- exporters/metric/stdout/stdout_test.go | 8 +- exporters/metric/test/test.go | 4 +- .../otlp/internal/transform/metric_test.go | 12 +-- exporters/otlp/otlp_integration_test.go | 22 +++--- exporters/otlp/otlp_metric_test.go | 8 +- sdk/export/metric/aggregator/aggregator.go | 2 +- .../metric/aggregator/aggregator_test.go | 2 +- sdk/export/metric/metric.go | 20 ++--- sdk/metric/aggregator/array/array.go | 2 + sdk/metric/aggregator/array/array_test.go | 8 +- sdk/metric/aggregator/ddsketch/ddsketch.go | 2 +- .../aggregator/ddsketch/ddsketch_test.go | 4 +- sdk/metric/aggregator/histogram/histogram.go | 2 +- .../aggregator/histogram/histogram_test.go | 6 +- sdk/metric/aggregator/minmaxsumcount/mmsc.go | 9 ++- .../aggregator/minmaxsumcount/mmsc_test.go | 6 +- sdk/metric/aggregator/sum/sum_test.go | 4 +- sdk/metric/benchmark_test.go | 50 ++++++------ sdk/metric/correct_test.go | 30 +++---- sdk/metric/doc.go | 79 ++++++------------- sdk/metric/histogram_stress_test.go | 2 +- sdk/metric/minmaxsumcount_stress_test.go | 2 +- sdk/metric/selector/simple/simple.go | 32 ++++---- sdk/metric/selector/simple/simple_test.go | 30 +++---- sdk/metric/stress_test.go | 14 ++-- 43 files changed, 321 insertions(+), 375 deletions(-) rename api/metric/{measure.go => valuerecorder.go} (51%) diff --git a/api/global/internal/benchmark_test.go b/api/global/internal/benchmark_test.go index 66a3728d1..017afbd95 100644 --- a/api/global/internal/benchmark_test.go +++ b/api/global/internal/benchmark_test.go @@ -59,7 +59,7 @@ func (*benchFixture) AggregatorFor(descriptor *metric.Descriptor) export.Aggrega switch descriptor.MetricKind() { case metric.CounterKind: return sum.New() - case metric.MeasureKind: + case metric.ValueRecorderKind: if strings.HasSuffix(descriptor.Name(), "minmaxsumcount") { return minmaxsumcount.New(descriptor) } else if strings.HasSuffix(descriptor.Name(), "ddsketch") { diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 070e65221..17485b745 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -82,9 +82,9 @@ func TestDirect(t *testing.T) { counter.Add(ctx, 1, labels1...) counter.Add(ctx, 1, labels1...) - measure := Must(meter1).NewFloat64Measure("test.measure") - measure.Record(ctx, 1, labels1...) - measure.Record(ctx, 2, labels1...) + valuerecorder := Must(meter1).NewFloat64ValueRecorder("test.valuerecorder") + valuerecorder.Record(ctx, 1, labels1...) + valuerecorder.Record(ctx, 2, labels1...) _ = Must(meter1).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) { result.Observe(1., labels1...) @@ -96,7 +96,7 @@ func TestDirect(t *testing.T) { result.Observe(2, labels2...) }) - second := Must(meter2).NewFloat64Measure("test.second") + second := Must(meter2).NewFloat64ValueRecorder("test.second") second.Record(ctx, 1, labels3...) second.Record(ctx, 2, labels3...) @@ -104,7 +104,7 @@ func TestDirect(t *testing.T) { global.SetMeterProvider(provider) counter.Add(ctx, 1, labels1...) - measure.Record(ctx, 3, labels1...) + valuerecorder.Record(ctx, 3, labels1...) second.Record(ctx, 3, labels3...) mock.RunAsyncInstruments() @@ -120,7 +120,7 @@ func TestDirect(t *testing.T) { Number: asInt(1), }, { - Name: "test.measure", + Name: "test.valuerecorder", LibraryName: "test1", Labels: asMap(labels1...), Number: asFloat(3), @@ -174,8 +174,8 @@ func TestBound(t *testing.T) { boundC.Add(ctx, 1) boundC.Add(ctx, 1) - measure := Must(glob).NewInt64Measure("test.measure") - boundM := measure.Bind(labels1...) + valuerecorder := Must(glob).NewInt64ValueRecorder("test.valuerecorder") + boundM := valuerecorder.Bind(labels1...) boundM.Record(ctx, 1) boundM.Record(ctx, 2) @@ -194,7 +194,7 @@ func TestBound(t *testing.T) { Number: asFloat(1), }, { - Name: "test.measure", + Name: "test.valuerecorder", LibraryName: "test", Labels: asMap(labels1...), Number: asInt(3), @@ -216,8 +216,8 @@ func TestUnbind(t *testing.T) { counter := Must(glob).NewFloat64Counter("test.counter") boundC := counter.Bind(labels1...) - measure := Must(glob).NewInt64Measure("test.measure") - boundM := measure.Bind(labels1...) + valuerecorder := Must(glob).NewInt64ValueRecorder("test.valuerecorder") + boundM := valuerecorder.Bind(labels1...) boundC.Unbind() boundM.Unbind() diff --git a/api/global/internal/registry_test.go b/api/global/internal/registry_test.go index 6e6af1407..14ae04dfd 100644 --- a/api/global/internal/registry_test.go +++ b/api/global/internal/registry_test.go @@ -36,11 +36,11 @@ var ( "counter.float64": func(name, libraryName string) (metric.InstrumentImpl, error) { return unwrap(MeterProvider().Meter(libraryName).NewFloat64Counter(name)) }, - "measure.int64": func(name, libraryName string) (metric.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewInt64Measure(name)) + "valuerecorder.int64": func(name, libraryName string) (metric.InstrumentImpl, error) { + return unwrap(MeterProvider().Meter(libraryName).NewInt64ValueRecorder(name)) }, - "measure.float64": func(name, libraryName string) (metric.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).NewFloat64Measure(name)) + "valuerecorder.float64": func(name, libraryName string) (metric.InstrumentImpl, error) { + return unwrap(MeterProvider().Meter(libraryName).NewFloat64ValueRecorder(name)) }, "observer.int64": func(name, libraryName string) (metric.InstrumentImpl, error) { return unwrap(MeterProvider().Meter(libraryName).RegisterInt64Observer(name, func(metric.Int64ObserverResult) {})) diff --git a/api/metric/api_test.go b/api/metric/api_test.go index 1395b8687..9a370a8d4 100644 --- a/api/metric/api_test.go +++ b/api/metric/api_test.go @@ -119,29 +119,29 @@ func TestCounter(t *testing.T) { } } -func TestMeasure(t *testing.T) { +func TestValueRecorder(t *testing.T) { { mockSDK, meter := mockTest.NewMeter() - m := Must(meter).NewFloat64Measure("test.measure.float") + m := Must(meter).NewFloat64ValueRecorder("test.valuerecorder.float") ctx := context.Background() labels := []kv.KeyValue{} m.Record(ctx, 42, labels...) boundInstrument := m.Bind(labels...) boundInstrument.Record(ctx, 42) meter.RecordBatch(ctx, labels, m.Measurement(42)) - t.Log("Testing float measure") + t.Log("Testing float valuerecorder") checkBatches(t, ctx, labels, mockSDK, metric.Float64NumberKind, m.SyncImpl()) } { mockSDK, meter := mockTest.NewMeter() - m := Must(meter).NewInt64Measure("test.measure.int") + m := Must(meter).NewInt64ValueRecorder("test.valuerecorder.int") ctx := context.Background() labels := []kv.KeyValue{kv.Int("I", 1)} m.Record(ctx, 42, labels...) boundInstrument := m.Bind(labels...) boundInstrument.Record(ctx, 42) meter.RecordBatch(ctx, labels, m.Measurement(42)) - t.Log("Testing int measure") + t.Log("Testing int valuerecorder") checkBatches(t, ctx, labels, mockSDK, metric.Int64NumberKind, m.SyncImpl()) } } @@ -309,10 +309,10 @@ func TestWrappedInstrumentError(t *testing.T) { impl := &testWrappedMeter{} meter := metric.WrapMeterImpl(impl, "test") - measure, err := meter.NewInt64Measure("test.measure") + valuerecorder, err := meter.NewInt64ValueRecorder("test.valuerecorder") require.Equal(t, err, metric.ErrSDKReturnedNilImpl) - require.NotNil(t, measure.SyncImpl()) + require.NotNil(t, valuerecorder.SyncImpl()) observer, err := meter.RegisterInt64Observer("test.observer", func(result metric.Int64ObserverResult) {}) diff --git a/api/metric/doc.go b/api/metric/doc.go index 127b33bd4..8249b6f6d 100644 --- a/api/metric/doc.go +++ b/api/metric/doc.go @@ -13,57 +13,37 @@ // limitations under the License. // metric package provides an API for reporting diagnostic -// measurements using four basic kinds of instruments. +// measurements using instruments categorized as follows: // -// The three basic kinds are: +// Synchronous instruments are called by the user with a Context. +// Asynchronous instruments are called by the SDK during collection. // -// - counters -// - measures -// - observers +// Additive instruments are semantically intended for capturing a sum. +// Non-additive instruments are intended for capturing a distribution. // -// All instruments report either float64 or int64 values. +// Additive instruments may be monotonic, in which case they are +// non-descreasing and naturally define a rate. // -// The primary object that handles metrics is Meter. Meter can be -// obtained from Provider. The implementations of the Meter and -// Provider are provided by SDK. Normally, the Meter is used directly -// only for the instrument creation and batch recording. +// The synchronous instrument names are: // -// Counters are instruments that are reporting a quantity or a sum. An -// example could be bank account balance or bytes downloaded. Counters -// can be created with either NewFloat64Counter or -// NewInt64Counter. Counters expect non-negative values by default to -// be reported. This can be changed with the WithMonotonic option -// (passing false as a parameter) passed to the Meter.New*Counter -// function - this allows reporting negative values. To report the new -// value, use an Add function. +// Counter: additive, monotonic +// UpDownCounter: additive +// ValueRecorder: non-additive // -// Measures are instruments that are reporting values that are -// recorded separately to figure out some statistical properties from -// those values (like average). An example could be temperature over -// time or lines of code in the project over time. Measures can be -// created with either NewFloat64Measure or NewInt64Measure. Measures -// by default take only non-negative values. This can be changed with -// the WithAbsolute option (passing false as a parameter) passed to -// the New*Measure function - this allows reporting negative values -// too. To report a new value, use the Record function. +// and the asynchronous instruments are: // -// Observers are instruments that are reporting a current state of a -// set of values. An example could be voltage or -// temperature. Observers can be created with either -// RegisterFloat64Observer or RegisterInt64Observer. Observers by -// default have no limitations about reported values - they can be -// less or greater than the last reported value. This can be changed -// with the WithMonotonic option passed to the Register*Observer -// function - this permits the reported values only to go -// up. Reporting of the new values happens asynchronously, with the -// use of a callback passed to the Register*Observer function. The -// callback can report multiple values. There is no unregister function. +// SumObserver: additive, monotonic +// UpDownSumOnserver: additive +// ValueObserver: non-additive // -// Counters and measures support creating bound instruments for a -// potentially more efficient reporting. The bound instruments have -// the same function names as the instruments (so a Counter bound -// instrument has Add, and a Measure bound instrument has Record). -// Bound Instruments can be created with the Bind function of the -// respective instrument. When done with the bound instrument, call -// Unbind on it. +// All instruments are provided with support for either float64 or +// int64 input values. +// +// The Meter interface supports allocating new instruments as well as +// interfaces for recording batches of synchronous measurements or +// asynchronous observations. To obtain a Meter, use a Provider. +// +// The Provider interface supports obtaining a named Meter interface. +// To obtain a Provider implementation, initialize and configure any +// compatible SDK. package metric // import "go.opentelemetry.io/otel/api/metric" diff --git a/api/metric/kind.go b/api/metric/kind.go index 63799ca96..38001e918 100644 --- a/api/metric/kind.go +++ b/api/metric/kind.go @@ -20,8 +20,8 @@ package metric type Kind int8 const ( - // MeasureKind indicates a Measure instrument. - MeasureKind Kind = iota + // ValueRecorderKind indicates a ValueRecorder instrument. + ValueRecorderKind Kind = iota // ObserverKind indicates an Observer instrument. ObserverKind // CounterKind indicates a Counter instrument. diff --git a/api/metric/kind_string.go b/api/metric/kind_string.go index f46c1463f..67113b120 100644 --- a/api/metric/kind_string.go +++ b/api/metric/kind_string.go @@ -8,14 +8,14 @@ func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} - _ = x[MeasureKind-0] + _ = x[ValueRecorderKind-0] _ = x[ObserverKind-1] _ = x[CounterKind-2] } -const _Kind_name = "MeasureKindObserverKindCounterKind" +const _Kind_name = "ValueRecorderKindObserverKindCounterKind" -var _Kind_index = [...]uint8{0, 11, 23, 34} +var _Kind_index = [...]uint8{0, 17, 29, 40} func (i Kind) String() string { if i < 0 || i >= Kind(len(_Kind_index)-1) { diff --git a/api/metric/meter.go b/api/metric/meter.go index e20b02b1e..5e95e2812 100644 --- a/api/metric/meter.go +++ b/api/metric/meter.go @@ -82,22 +82,22 @@ func (m Meter) NewFloat64Counter(name string, options ...Option) (Float64Counter m.newSync(name, CounterKind, Float64NumberKind, options)) } -// NewInt64Measure creates a new integer Measure instrument with the +// NewInt64ValueRecorder creates a new integer ValueRecorder instrument with the // given name, customized with options. May return an error if the // name is invalid (e.g., empty) or improperly registered (e.g., // duplicate registration). -func (m Meter) NewInt64Measure(name string, opts ...Option) (Int64Measure, error) { - return wrapInt64MeasureInstrument( - m.newSync(name, MeasureKind, Int64NumberKind, opts)) +func (m Meter) NewInt64ValueRecorder(name string, opts ...Option) (Int64ValueRecorder, error) { + return wrapInt64ValueRecorderInstrument( + m.newSync(name, ValueRecorderKind, Int64NumberKind, opts)) } -// NewFloat64Measure creates a new floating point Measure with the +// NewFloat64ValueRecorder creates a new floating point ValueRecorder with the // given name, customized with options. May return an error if the // name is invalid (e.g., empty) or improperly registered (e.g., // duplicate registration). -func (m Meter) NewFloat64Measure(name string, opts ...Option) (Float64Measure, error) { - return wrapFloat64MeasureInstrument( - m.newSync(name, MeasureKind, Float64NumberKind, opts)) +func (m Meter) NewFloat64ValueRecorder(name string, opts ...Option) (Float64ValueRecorder, error) { + return wrapFloat64ValueRecorderInstrument( + m.newSync(name, ValueRecorderKind, Float64NumberKind, opts)) } // RegisterInt64Observer creates a new integer Observer instrument diff --git a/api/metric/must.go b/api/metric/must.go index ecd47b0e0..b747932f3 100644 --- a/api/metric/must.go +++ b/api/metric/must.go @@ -53,20 +53,20 @@ func (mm MeterMust) NewFloat64Counter(name string, cos ...Option) Float64Counter } } -// NewInt64Measure calls `Meter.NewInt64Measure` and returns the +// NewInt64ValueRecorder calls `Meter.NewInt64ValueRecorder` and returns the // instrument, panicking if it encounters an error. -func (mm MeterMust) NewInt64Measure(name string, mos ...Option) Int64Measure { - if inst, err := mm.meter.NewInt64Measure(name, mos...); err != nil { +func (mm MeterMust) NewInt64ValueRecorder(name string, mos ...Option) Int64ValueRecorder { + if inst, err := mm.meter.NewInt64ValueRecorder(name, mos...); err != nil { panic(err) } else { return inst } } -// NewFloat64Measure calls `Meter.NewFloat64Measure` and returns the +// NewFloat64ValueRecorder calls `Meter.NewFloat64ValueRecorder` and returns the // instrument, panicking if it encounters an error. -func (mm MeterMust) NewFloat64Measure(name string, mos ...Option) Float64Measure { - if inst, err := mm.meter.NewFloat64Measure(name, mos...); err != nil { +func (mm MeterMust) NewFloat64ValueRecorder(name string, mos ...Option) Float64ValueRecorder { + if inst, err := mm.meter.NewFloat64ValueRecorder(name, mos...); err != nil { panic(err) } else { return inst diff --git a/api/metric/registry/registry_test.go b/api/metric/registry/registry_test.go index 55eea312f..51f8392a1 100644 --- a/api/metric/registry/registry_test.go +++ b/api/metric/registry/registry_test.go @@ -37,11 +37,11 @@ var ( "counter.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { return unwrap(m.NewFloat64Counter(name)) }, - "measure.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { - return unwrap(m.NewInt64Measure(name)) + "valuerecorder.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { + return unwrap(m.NewInt64ValueRecorder(name)) }, - "measure.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { - return unwrap(m.NewFloat64Measure(name)) + "valuerecorder.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { + return unwrap(m.NewFloat64ValueRecorder(name)) }, "observer.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { return unwrap(m.RegisterInt64Observer(name, func(metric.Int64ObserverResult) {})) diff --git a/api/metric/sdkapi.go b/api/metric/sdkapi.go index c9b902dc8..c7a6fe4c5 100644 --- a/api/metric/sdkapi.go +++ b/api/metric/sdkapi.go @@ -53,7 +53,7 @@ type InstrumentImpl interface { } // SyncImpl is the implementation-level interface to a generic -// synchronous instrument (e.g., Measure and Counter instruments). +// synchronous instrument (e.g., ValueRecorder and Counter instruments). type SyncImpl interface { InstrumentImpl diff --git a/api/metric/sync.go b/api/metric/sync.go index 6b8d3a2a3..66e99c285 100644 --- a/api/metric/sync.go +++ b/api/metric/sync.go @@ -174,22 +174,22 @@ func wrapFloat64CounterInstrument(syncInst SyncImpl, err error) (Float64Counter, return Float64Counter{syncInstrument: common}, err } -// wrapInt64MeasureInstrument returns an `Int64Measure` from a +// wrapInt64ValueRecorderInstrument returns an `Int64ValueRecorder` from a // `SyncImpl`. An error will be generated if the // `SyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func wrapInt64MeasureInstrument(syncInst SyncImpl, err error) (Int64Measure, error) { +func wrapInt64ValueRecorderInstrument(syncInst SyncImpl, err error) (Int64ValueRecorder, error) { common, err := checkNewSync(syncInst, err) - return Int64Measure{syncInstrument: common}, err + return Int64ValueRecorder{syncInstrument: common}, err } -// wrapFloat64MeasureInstrument returns an `Float64Measure` from a +// wrapFloat64ValueRecorderInstrument returns an `Float64ValueRecorder` from a // `SyncImpl`. An error will be generated if the // `SyncImpl` is nil (in which case a No-op is substituted), // otherwise the error passes through. -func wrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure, error) { +func wrapFloat64ValueRecorderInstrument(syncInst SyncImpl, err error) (Float64ValueRecorder, error) { common, err := checkNewSync(syncInst, err) - return Float64Measure{syncInstrument: common}, err + return Float64ValueRecorder{syncInstrument: common}, err } // wrapInt64ObserverInstrument returns an `Int64Observer` from a diff --git a/api/metric/measure.go b/api/metric/valuerecorder.go similarity index 51% rename from api/metric/measure.go rename to api/metric/valuerecorder.go index 11dd215ee..f4723fb98 100644 --- a/api/metric/measure.go +++ b/api/metric/valuerecorder.go @@ -20,78 +20,78 @@ import ( "go.opentelemetry.io/otel/api/kv" ) -// Float64Measure is a metric that records float64 values. -type Float64Measure struct { +// Float64ValueRecorder is a metric that records float64 values. +type Float64ValueRecorder struct { syncInstrument } -// Int64Measure is a metric that records int64 values. -type Int64Measure struct { +// Int64ValueRecorder is a metric that records int64 values. +type Int64ValueRecorder struct { syncInstrument } -// BoundFloat64Measure is a bound instrument for Float64Measure. +// BoundFloat64ValueRecorder is a bound instrument for Float64ValueRecorder. // // It inherits the Unbind function from syncBoundInstrument. -type BoundFloat64Measure struct { +type BoundFloat64ValueRecorder struct { syncBoundInstrument } -// BoundInt64Measure is a bound instrument for Int64Measure. +// BoundInt64ValueRecorder is a bound instrument for Int64ValueRecorder. // // It inherits the Unbind function from syncBoundInstrument. -type BoundInt64Measure struct { +type BoundInt64ValueRecorder struct { syncBoundInstrument } -// Bind creates a bound instrument for this measure. The labels are +// Bind creates a bound instrument for this ValueRecorder. The labels are // associated with values recorded via subsequent calls to Record. -func (c Float64Measure) Bind(labels ...kv.KeyValue) (h BoundFloat64Measure) { +func (c Float64ValueRecorder) Bind(labels ...kv.KeyValue) (h BoundFloat64ValueRecorder) { h.syncBoundInstrument = c.bind(labels) return } -// Bind creates a bound instrument for this measure. The labels are +// Bind creates a bound instrument for this ValueRecorder. The labels are // associated with values recorded via subsequent calls to Record. -func (c Int64Measure) Bind(labels ...kv.KeyValue) (h BoundInt64Measure) { +func (c Int64ValueRecorder) Bind(labels ...kv.KeyValue) (h BoundInt64ValueRecorder) { h.syncBoundInstrument = c.bind(labels) return } // Measurement creates a Measurement object to use with batch // recording. -func (c Float64Measure) Measurement(value float64) Measurement { +func (c Float64ValueRecorder) Measurement(value float64) Measurement { return c.float64Measurement(value) } // Measurement creates a Measurement object to use with batch // recording. -func (c Int64Measure) Measurement(value int64) Measurement { +func (c Int64ValueRecorder) Measurement(value int64) Measurement { return c.int64Measurement(value) } -// Record adds a new value to the list of measure's records. The +// Record adds a new value to the list of ValueRecorder's records. The // labels should contain the keys and values to be associated with // this value. -func (c Float64Measure) Record(ctx context.Context, value float64, labels ...kv.KeyValue) { +func (c Float64ValueRecorder) Record(ctx context.Context, value float64, labels ...kv.KeyValue) { c.directRecord(ctx, NewFloat64Number(value), labels) } -// Record adds a new value to the list of measure's records. The +// Record adds a new value to the ValueRecorder's distribution. The // labels should contain the keys and values to be associated with // this value. -func (c Int64Measure) Record(ctx context.Context, value int64, labels ...kv.KeyValue) { +func (c Int64ValueRecorder) Record(ctx context.Context, value int64, labels ...kv.KeyValue) { c.directRecord(ctx, NewInt64Number(value), labels) } -// Record adds a new value to the list of measure's records using the labels -// previously bound to the measure via Bind() -func (b BoundFloat64Measure) Record(ctx context.Context, value float64) { +// Record adds a new value to the ValueRecorder's distribution using the labels +// previously bound to the ValueRecorder via Bind(). +func (b BoundFloat64ValueRecorder) Record(ctx context.Context, value float64) { b.directRecord(ctx, NewFloat64Number(value)) } -// Record adds a new value to the list of measure's records using the labels -// previously bound to the measure via Bind() -func (b BoundInt64Measure) Record(ctx context.Context, value int64) { +// Record adds a new value to the ValueRecorder's distribution using the labels +// previously bound to the ValueRecorder via Bind(). +func (b BoundInt64ValueRecorder) Record(ctx context.Context, value int64) { b.directRecord(ctx, NewInt64Number(value)) } diff --git a/example/basic/main.go b/example/basic/main.go index 9a5b05983..84470d10b 100644 --- a/example/basic/main.go +++ b/example/basic/main.go @@ -80,7 +80,7 @@ func main() { metric.WithDescription("An observer set to 1.0"), ) - measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two") + valuerecorderTwo := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two") ctx := context.Background() @@ -89,8 +89,8 @@ func main() { barKey.String("bar1"), ) - measure := measureTwo.Bind(commonLabels...) - defer measure.Unbind() + valuerecorder := valuerecorderTwo.Bind(commonLabels...) + defer valuerecorder.Unbind() err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error { @@ -103,7 +103,7 @@ func main() { correlation.NewContext(ctx, anotherKey.String("xyz")), commonLabels, - measureTwo.Measurement(2.0), + valuerecorderTwo.Measurement(2.0), ) return tracer.WithSpan( @@ -114,7 +114,7 @@ func main() { trace.SpanFromContext(ctx).AddEvent(ctx, "Sub span event") - measure.Record(ctx, 1.3) + valuerecorder.Record(ctx, 1.3) return nil }, diff --git a/example/prometheus/main.go b/example/prometheus/main.go index 6c0282801..f9a5cf702 100644 --- a/example/prometheus/main.go +++ b/example/prometheus/main.go @@ -60,11 +60,11 @@ func main() { result.Observe(value, labels...) } _ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", cb, - metric.WithDescription("A measure set to 1.0"), + metric.WithDescription("An observer set to 1.0"), ) - measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two") - measureThree := metric.Must(meter).NewFloat64Counter("ex.com.three") + valuerecorder := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two") + counter := metric.Must(meter).NewFloat64Counter("ex.com.three") commonLabels := []kv.KeyValue{lemonsKey.Int(10), kv.String("A", "1"), kv.String("B", "2"), kv.String("C", "3")} notSoCommonLabels := []kv.KeyValue{lemonsKey.Int(13)} @@ -78,8 +78,8 @@ func main() { meter.RecordBatch( ctx, commonLabels, - measureTwo.Measurement(2.0), - measureThree.Measurement(12.0), + valuerecorder.Measurement(2.0), + counter.Measurement(12.0), ) time.Sleep(5 * time.Second) @@ -91,8 +91,8 @@ func main() { meter.RecordBatch( ctx, notSoCommonLabels, - measureTwo.Measurement(2.0), - measureThree.Measurement(22.0), + valuerecorder.Measurement(2.0), + counter.Measurement(22.0), ) time.Sleep(5 * time.Second) @@ -104,8 +104,8 @@ func main() { meter.RecordBatch( ctx, commonLabels, - measureTwo.Measurement(12.0), - measureThree.Measurement(13.0), + valuerecorder.Measurement(12.0), + counter.Measurement(13.0), ) time.Sleep(100 * time.Second) diff --git a/exporters/metric/prometheus/prometheus.go b/exporters/metric/prometheus/prometheus.go index 2d8ec76de..5af88a6b7 100644 --- a/exporters/metric/prometheus/prometheus.go +++ b/exporters/metric/prometheus/prometheus.go @@ -147,7 +147,7 @@ func InstallNewPipeline(config Config) (*push.Controller, http.HandlerFunc, erro // NewExportPipeline sets up a complete export pipeline with the recommended setup, // chaining a NewRawExporter into the recommended selectors and integrators. func NewExportPipeline(config Config, period time.Duration) (*push.Controller, http.HandlerFunc, error) { - selector := simple.NewWithHistogramMeasure(config.DefaultHistogramBoundaries) + selector := simple.NewWithHistogramDistribution(config.DefaultHistogramBoundaries) exporter, err := NewRawExporter(config) if err != nil { return nil, nil, err @@ -220,7 +220,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { } } else if dist, ok := agg.(aggregator.Distribution); ok { // TODO: summaries values are never being resetted. - // As measures are recorded, new records starts to have less impact on these summaries. + // As measurements are recorded, new records starts to have less impact on these summaries. // We should implement an solution that is similar to the Prometheus Clients // using a rolling window for summaries could be a solution. // diff --git a/exporters/metric/prometheus/prometheus_test.go b/exporters/metric/prometheus/prometheus_test.go index 362df65a6..0505281a4 100644 --- a/exporters/metric/prometheus/prometheus_test.go +++ b/exporters/metric/prometheus/prometheus_test.go @@ -45,10 +45,10 @@ func TestPrometheusExporter(t *testing.T) { "counter", metric.CounterKind, metric.Float64NumberKind) lastValue := metric.NewDescriptor( "lastvalue", metric.ObserverKind, metric.Float64NumberKind) - measure := metric.NewDescriptor( - "measure", metric.MeasureKind, metric.Float64NumberKind) - histogramMeasure := metric.NewDescriptor( - "histogram_measure", metric.MeasureKind, metric.Float64NumberKind) + valuerecorder := metric.NewDescriptor( + "valuerecorder", metric.ValueRecorderKind, metric.Float64NumberKind) + histogramValueRecorder := metric.NewDescriptor( + "histogram_valuerecorder", metric.ValueRecorderKind, metric.Float64NumberKind) labels := []kv.KeyValue{ kv.Key("A").String("B"), @@ -61,26 +61,26 @@ func TestPrometheusExporter(t *testing.T) { checkpointSet.AddLastValue(&lastValue, 13.2, labels...) expected = append(expected, `lastvalue{A="B",C="D"} 13.2`) - checkpointSet.AddMeasure(&measure, 13, labels...) - checkpointSet.AddMeasure(&measure, 15, labels...) - checkpointSet.AddMeasure(&measure, 17, labels...) - expected = append(expected, `measure{A="B",C="D",quantile="0.5"} 15`) - expected = append(expected, `measure{A="B",C="D",quantile="0.9"} 17`) - expected = append(expected, `measure{A="B",C="D",quantile="0.99"} 17`) - expected = append(expected, `measure_sum{A="B",C="D"} 45`) - expected = append(expected, `measure_count{A="B",C="D"} 3`) + checkpointSet.AddValueRecorder(&valuerecorder, 13, labels...) + checkpointSet.AddValueRecorder(&valuerecorder, 15, labels...) + checkpointSet.AddValueRecorder(&valuerecorder, 17, labels...) + expected = append(expected, `valuerecorder{A="B",C="D",quantile="0.5"} 15`) + expected = append(expected, `valuerecorder{A="B",C="D",quantile="0.9"} 17`) + expected = append(expected, `valuerecorder{A="B",C="D",quantile="0.99"} 17`) + expected = append(expected, `valuerecorder_sum{A="B",C="D"} 45`) + expected = append(expected, `valuerecorder_count{A="B",C="D"} 3`) boundaries := []metric.Number{metric.NewFloat64Number(-0.5), metric.NewFloat64Number(1)} - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.6, labels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.4, labels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 0.6, labels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 20, labels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.6, labels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.4, labels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 0.6, labels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 20, labels...) - expected = append(expected, `histogram_measure_bucket{A="B",C="D",le="+Inf"} 4`) - expected = append(expected, `histogram_measure_bucket{A="B",C="D",le="-0.5"} 1`) - expected = append(expected, `histogram_measure_bucket{A="B",C="D",le="1"} 3`) - expected = append(expected, `histogram_measure_count{A="B",C="D"} 4`) - expected = append(expected, `histogram_measure_sum{A="B",C="D"} 19.6`) + expected = append(expected, `histogram_valuerecorder_bucket{A="B",C="D",le="+Inf"} 4`) + expected = append(expected, `histogram_valuerecorder_bucket{A="B",C="D",le="-0.5"} 1`) + expected = append(expected, `histogram_valuerecorder_bucket{A="B",C="D",le="1"} 3`) + expected = append(expected, `histogram_valuerecorder_count{A="B",C="D"} 4`) + expected = append(expected, `histogram_valuerecorder_sum{A="B",C="D"} 19.6`) missingLabels := []kv.KeyValue{ kv.Key("A").String("E"), @@ -93,25 +93,25 @@ func TestPrometheusExporter(t *testing.T) { checkpointSet.AddLastValue(&lastValue, 32, missingLabels...) expected = append(expected, `lastvalue{A="E",C=""} 32`) - checkpointSet.AddMeasure(&measure, 19, missingLabels...) - expected = append(expected, `measure{A="E",C="",quantile="0.5"} 19`) - expected = append(expected, `measure{A="E",C="",quantile="0.9"} 19`) - expected = append(expected, `measure{A="E",C="",quantile="0.99"} 19`) - expected = append(expected, `measure_count{A="E",C=""} 1`) - expected = append(expected, `measure_sum{A="E",C=""} 19`) + checkpointSet.AddValueRecorder(&valuerecorder, 19, missingLabels...) + expected = append(expected, `valuerecorder{A="E",C="",quantile="0.5"} 19`) + expected = append(expected, `valuerecorder{A="E",C="",quantile="0.9"} 19`) + expected = append(expected, `valuerecorder{A="E",C="",quantile="0.99"} 19`) + expected = append(expected, `valuerecorder_count{A="E",C=""} 1`) + expected = append(expected, `valuerecorder_sum{A="E",C=""} 19`) boundaries = []metric.Number{metric.NewFloat64Number(0), metric.NewFloat64Number(1)} - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.6, missingLabels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.4, missingLabels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, -0.1, missingLabels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 15, missingLabels...) - checkpointSet.AddHistogramMeasure(&histogramMeasure, boundaries, 15, missingLabels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.6, missingLabels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.4, missingLabels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, -0.1, missingLabels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 15, missingLabels...) + checkpointSet.AddHistogramValueRecorder(&histogramValueRecorder, boundaries, 15, missingLabels...) - expected = append(expected, `histogram_measure_bucket{A="E",C="",le="+Inf"} 5`) - expected = append(expected, `histogram_measure_bucket{A="E",C="",le="0"} 3`) - expected = append(expected, `histogram_measure_bucket{A="E",C="",le="1"} 3`) - expected = append(expected, `histogram_measure_count{A="E",C=""} 5`) - expected = append(expected, `histogram_measure_sum{A="E",C=""} 28.9`) + expected = append(expected, `histogram_valuerecorder_bucket{A="E",C="",le="+Inf"} 5`) + expected = append(expected, `histogram_valuerecorder_bucket{A="E",C="",le="0"} 3`) + expected = append(expected, `histogram_valuerecorder_bucket{A="E",C="",le="1"} 3`) + expected = append(expected, `histogram_valuerecorder_count{A="E",C=""} 5`) + expected = append(expected, `histogram_valuerecorder_sum{A="E",C=""} 28.9`) compareExport(t, exporter, checkpointSet, expected) } diff --git a/exporters/metric/stdout/stdout.go b/exporters/metric/stdout/stdout.go index 04e39e6b1..d22b5f070 100644 --- a/exporters/metric/stdout/stdout.go +++ b/exporters/metric/stdout/stdout.go @@ -53,8 +53,8 @@ type Config struct { // useful to create deterministic test conditions. DoNotPrintTime bool - // Quantiles are the desired aggregation quantiles for measure - // metric data, used when the configured aggregator supports + // Quantiles are the desired aggregation quantiles for distribution + // summaries, used when the configured aggregator supports // quantiles. // // Note: this exporter is meant as a demonstration; a real @@ -133,7 +133,7 @@ func InstallNewPipeline(config Config, opts ...push.Option) (*push.Controller, e // NewExportPipeline sets up a complete export pipeline with the recommended setup, // chaining a NewRawExporter into the recommended selectors and integrators. func NewExportPipeline(config Config, period time.Duration, opts ...push.Option) (*push.Controller, error) { - selector := simple.NewWithExactMeasure() + selector := simple.NewWithExactDistribution() exporter, err := NewRawExporter(config) if err != nil { return nil, err diff --git a/exporters/metric/stdout/stdout_test.go b/exporters/metric/stdout/stdout_test.go index a5f94df6c..918c47b8b 100644 --- a/exporters/metric/stdout/stdout_test.go +++ b/exporters/metric/stdout/stdout_test.go @@ -177,7 +177,7 @@ func TestStdoutMinMaxSumCount(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueRecorderKind, metric.Float64NumberKind) magg := minmaxsumcount.New(&desc) aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(123.456), &desc) aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(876.543), &desc) @@ -190,14 +190,14 @@ func TestStdoutMinMaxSumCount(t *testing.T) { require.Equal(t, `{"updates":[{"name":"test.name{A=B,C=D}","min":123.456,"max":876.543,"sum":999.999,"count":2}]}`, fix.Output()) } -func TestStdoutMeasureFormat(t *testing.T) { +func TestStdoutValueRecorderFormat(t *testing.T) { fix := newFixture(t, nil, stdout.Config{ PrettyPrint: true, }) checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueRecorderKind, metric.Float64NumberKind) magg := array.New() for i := 0; i < 1000; i++ { @@ -238,7 +238,7 @@ func TestStdoutMeasureFormat(t *testing.T) { } func TestStdoutNoData(t *testing.T) { - desc := metric.NewDescriptor("test.name", metric.MeasureKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueRecorderKind, metric.Float64NumberKind) for name, tc := range map[string]export.Aggregator{ "ddsketch": ddsketch.New(ddsketch.NewDefaultConfig(), &desc), "minmaxsumcount": minmaxsumcount.New(&desc), diff --git a/exporters/metric/test/test.go b/exporters/metric/test/test.go index a7dca90d1..bc49cd9c9 100644 --- a/exporters/metric/test/test.go +++ b/exporters/metric/test/test.go @@ -88,11 +88,11 @@ func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels .. p.updateAggregator(desc, sum.New(), v, labels...) } -func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) { +func (p *CheckpointSet) AddValueRecorder(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) { p.updateAggregator(desc, array.New(), v, labels...) } -func (p *CheckpointSet) AddHistogramMeasure(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...kv.KeyValue) { +func (p *CheckpointSet) AddHistogramValueRecorder(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...kv.KeyValue) { p.updateAggregator(desc, histogram.New(desc, boundaries), v, labels...) } diff --git a/exporters/otlp/internal/transform/metric_test.go b/exporters/otlp/internal/transform/metric_test.go index 57e0388a9..79f71e187 100644 --- a/exporters/otlp/internal/transform/metric_test.go +++ b/exporters/otlp/internal/transform/metric_test.go @@ -111,7 +111,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { }{ { "mmsc-test-a", - metric.MeasureKind, + metric.ValueRecorderKind, "test-a-description", unit.Dimensionless, metric.Int64NumberKind, @@ -160,7 +160,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) { } func TestMinMaxSumCountDatapoints(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, metric.Int64NumberKind) + desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.Int64NumberKind) labels := label.NewSet() mmsc := minmaxsumcount.New(&desc) assert.NoError(t, mmsc.Update(context.Background(), 1, &desc)) @@ -228,7 +228,7 @@ func TestSumMetricDescriptor(t *testing.T) { }, { "sum-test-b", - metric.MeasureKind, // This shouldn't change anything. + metric.ValueRecorderKind, // This shouldn't change anything. "test-b-description", unit.Milliseconds, metric.Float64NumberKind, @@ -257,7 +257,7 @@ func TestSumMetricDescriptor(t *testing.T) { } func TestSumInt64DataPoints(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, metric.Int64NumberKind) + desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.Int64NumberKind) labels := label.NewSet() s := sumAgg.New() assert.NoError(t, s.Update(context.Background(), metric.Number(1), &desc)) @@ -271,7 +271,7 @@ func TestSumInt64DataPoints(t *testing.T) { } func TestSumFloat64DataPoints(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.Float64NumberKind) labels := label.NewSet() s := sumAgg.New() assert.NoError(t, s.Update(context.Background(), metric.NewFloat64Number(1), &desc)) @@ -285,7 +285,7 @@ func TestSumFloat64DataPoints(t *testing.T) { } func TestSumErrUnknownValueType(t *testing.T) { - desc := metric.NewDescriptor("", metric.MeasureKind, metric.NumberKind(-1)) + desc := metric.NewDescriptor("", metric.ValueRecorderKind, metric.NumberKind(-1)) labels := label.NewSet() s := sumAgg.New() _, err := sum(&desc, &labels, s) diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go index 79121a292..624bd4a07 100644 --- a/exporters/otlp/otlp_integration_test.go +++ b/exporters/otlp/otlp_integration_test.go @@ -109,7 +109,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) span.End() } - selector := simple.NewWithExactMeasure() + selector := simple.NewWithExactDistribution() integrator := integrator.New(selector, true) pusher := push.New(integrator, exp, 60*time.Second) pusher.Start() @@ -124,12 +124,12 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) val int64 } instruments := map[string]data{ - "test-int64-counter": {metric.CounterKind, metricapi.Int64NumberKind, 1}, - "test-float64-counter": {metric.CounterKind, metricapi.Float64NumberKind, 1}, - "test-int64-measure": {metric.MeasureKind, metricapi.Int64NumberKind, 2}, - "test-float64-measure": {metric.MeasureKind, metricapi.Float64NumberKind, 2}, - "test-int64-observer": {metric.ObserverKind, metricapi.Int64NumberKind, 3}, - "test-float64-observer": {metric.ObserverKind, metricapi.Float64NumberKind, 3}, + "test-int64-counter": {metric.CounterKind, metricapi.Int64NumberKind, 1}, + "test-float64-counter": {metric.CounterKind, metricapi.Float64NumberKind, 1}, + "test-int64-valuerecorder": {metric.ValueRecorderKind, metricapi.Int64NumberKind, 2}, + "test-float64-valuerecorder": {metric.ValueRecorderKind, metricapi.Float64NumberKind, 2}, + "test-int64-observer": {metric.ObserverKind, metricapi.Int64NumberKind, 3}, + "test-float64-observer": {metric.ObserverKind, metricapi.Float64NumberKind, 3}, } for name, data := range instruments { switch data.iKind { @@ -142,12 +142,12 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) default: assert.Failf(t, "unsupported number testing kind", data.nKind.String()) } - case metric.MeasureKind: + case metric.ValueRecorderKind: switch data.nKind { case metricapi.Int64NumberKind: - metricapi.Must(meter).NewInt64Measure(name).Record(ctx, data.val, labels...) + metricapi.Must(meter).NewInt64ValueRecorder(name).Record(ctx, data.val, labels...) case metricapi.Float64NumberKind: - metricapi.Must(meter).NewFloat64Measure(name).Record(ctx, float64(data.val), labels...) + metricapi.Must(meter).NewFloat64ValueRecorder(name).Record(ctx, float64(data.val), labels...) default: assert.Failf(t, "unsupported number testing kind", data.nKind.String()) } @@ -246,7 +246,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) default: assert.Failf(t, "invalid number kind", data.nKind.String()) } - case metric.MeasureKind, metric.ObserverKind: + case metric.ValueRecorderKind, metric.ObserverKind: assert.Equal(t, metricpb.MetricDescriptor_SUMMARY.String(), desc.GetType().String()) m.GetSummaryDataPoints() if dp := m.GetSummaryDataPoints(); assert.Len(t, dp, 1) { diff --git a/exporters/otlp/otlp_metric_test.go b/exporters/otlp/otlp_metric_test.go index 0471d0add..4d72d541a 100644 --- a/exporters/otlp/otlp_metric_test.go +++ b/exporters/otlp/otlp_metric_test.go @@ -188,10 +188,10 @@ func TestNoGroupingExport(t *testing.T) { ) } -func TestMeasureMetricGroupingExport(t *testing.T) { +func TestValuerecorderMetricGroupingExport(t *testing.T) { r := record{ - "measure", - metric.MeasureKind, + "valuerecorder", + metric.ValueRecorderKind, metric.Int64NumberKind, nil, nil, @@ -205,7 +205,7 @@ func TestMeasureMetricGroupingExport(t *testing.T) { Metrics: []*metricpb.Metric{ { MetricDescriptor: &metricpb.MetricDescriptor{ - Name: "measure", + Name: "valuerecorder", Type: metricpb.MetricDescriptor_SUMMARY, Labels: []*commonpb.StringKeyValue{ { diff --git a/sdk/export/metric/aggregator/aggregator.go b/sdk/export/metric/aggregator/aggregator.go index df1285108..660e83ef3 100644 --- a/sdk/export/metric/aggregator/aggregator.go +++ b/sdk/export/metric/aggregator/aggregator.go @@ -116,7 +116,7 @@ func NewInconsistentMergeError(a1, a2 export.Aggregator) error { // RangeTest is a commmon routine for testing for valid input values. // This rejects NaN values. This rejects negative values when the // metric instrument does not support negative values, including -// monotonic counter metrics and absolute measure metrics. +// monotonic counter metrics and absolute ValueRecorder metrics. func RangeTest(number metric.Number, descriptor *metric.Descriptor) error { numberKind := descriptor.NumberKind() diff --git a/sdk/export/metric/aggregator/aggregator_test.go b/sdk/export/metric/aggregator/aggregator_test.go index 1907b92b7..0083a71a2 100644 --- a/sdk/export/metric/aggregator/aggregator_test.go +++ b/sdk/export/metric/aggregator/aggregator_test.go @@ -86,7 +86,7 @@ func TestNaNTest(t *testing.T) { t.Run(nkind.String(), func(t *testing.T) { for _, mkind := range []metric.Kind{ metric.CounterKind, - metric.MeasureKind, + metric.ValueRecorderKind, metric.ObserverKind, } { desc := metric.NewDescriptor( diff --git a/sdk/export/metric/metric.go b/sdk/export/metric/metric.go index 5b3a19a8f..c2d583173 100644 --- a/sdk/export/metric/metric.go +++ b/sdk/export/metric/metric.go @@ -100,22 +100,16 @@ type AggregationSelector interface { } // Aggregator implements a specific aggregation behavior, e.g., a -// behavior to track a sequence of updates to a counter, a measure, or -// an observer instrument. For the most part, counter semantics are -// fixed and the provided implementation should be used. Measure and -// observer metrics offer a wide range of potential tradeoffs and -// several implementations are provided. -// -// Aggregators are meant to compute the change (i.e., delta) in state -// from one checkpoint to the next, with the exception of LastValue -// aggregators. LastValue aggregators are required to maintain the last -// value across checkpoints. +// behavior to track a sequence of updates to an instrument. Sum-only +// instruments commonly use a simple Sum aggregator, but for the +// distribution instruments (ValueRecorder, ValueObserver) there are a +// number of possible aggregators with different cost and accuracy +// tradeoffs. // // Note that any Aggregator may be attached to any instrument--this is // the result of the OpenTelemetry API/SDK separation. It is possible -// to attach a counter aggregator to a Measure instrument (to compute -// a simple sum) or a LastValue aggregator to a measure instrument (to -// compute the last value). +// to attach a Sum aggregator to a ValueRecorder instrument or a +// MinMaxSumCount aggregator to a Counter instrument. type Aggregator interface { // Update receives a new measured value and incorporates it // into the aggregation. Update() calls may arrive diff --git a/sdk/metric/aggregator/array/array.go b/sdk/metric/aggregator/array/array.go index 38168bcc2..2d92a54fe 100644 --- a/sdk/metric/aggregator/array/array.go +++ b/sdk/metric/aggregator/array/array.go @@ -27,6 +27,8 @@ import ( ) type ( + // Aggregator aggregates events that form a distribution, keeping + // an array with the exact set of values. Aggregator struct { // ckptSum needs to be aligned for 64-bit atomic operations. ckptSum metric.Number diff --git a/sdk/metric/aggregator/array/array_test.go b/sdk/metric/aggregator/array/array_test.go index 87ea6d98f..2c3efb706 100644 --- a/sdk/metric/aggregator/array/array_test.go +++ b/sdk/metric/aggregator/array/array_test.go @@ -50,7 +50,7 @@ type updateTest struct { } func (ut *updateTest) run(t *testing.T, profile test.Profile) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg := New() @@ -118,7 +118,7 @@ type mergeTest struct { func (mt *mergeTest) run(t *testing.T, profile test.Profile) { ctx := context.Background() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg1 := New() agg2 := New() @@ -215,7 +215,7 @@ func TestArrayErrors(t *testing.T) { ctx := context.Background() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) test.CheckedUpdate(t, agg, metric.Number(0), descriptor) @@ -243,7 +243,7 @@ func TestArrayErrors(t *testing.T) { } func TestArrayFloat64(t *testing.T) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, metric.Float64NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, metric.Float64NumberKind) fpsf := func(sign int) []float64 { // Check behavior of a bunch of odd floating diff --git a/sdk/metric/aggregator/ddsketch/ddsketch.go b/sdk/metric/aggregator/ddsketch/ddsketch.go index a6b95da15..197d95e4d 100644 --- a/sdk/metric/aggregator/ddsketch/ddsketch.go +++ b/sdk/metric/aggregator/ddsketch/ddsketch.go @@ -29,7 +29,7 @@ import ( // Config is an alias for the underlying DDSketch config object. type Config = sdk.Config -// Aggregator aggregates measure events. +// Aggregator aggregates events into a distribution. type Aggregator struct { lock sync.Mutex cfg *Config diff --git a/sdk/metric/aggregator/ddsketch/ddsketch_test.go b/sdk/metric/aggregator/ddsketch/ddsketch_test.go index 22a39b568..cc68359de 100644 --- a/sdk/metric/aggregator/ddsketch/ddsketch_test.go +++ b/sdk/metric/aggregator/ddsketch/ddsketch_test.go @@ -33,7 +33,7 @@ type updateTest struct { func (ut *updateTest) run(t *testing.T, profile test.Profile) { ctx := context.Background() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg := New(NewDefaultConfig(), descriptor) all := test.NewNumbers(profile.NumberKind) @@ -92,7 +92,7 @@ type mergeTest struct { func (mt *mergeTest) run(t *testing.T, profile test.Profile) { ctx := context.Background() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg1 := New(NewDefaultConfig(), descriptor) agg2 := New(NewDefaultConfig(), descriptor) diff --git a/sdk/metric/aggregator/histogram/histogram.go b/sdk/metric/aggregator/histogram/histogram.go index f861d9651..6566dab91 100644 --- a/sdk/metric/aggregator/histogram/histogram.go +++ b/sdk/metric/aggregator/histogram/histogram.go @@ -51,7 +51,7 @@ var _ aggregator.Sum = &Aggregator{} var _ aggregator.Count = &Aggregator{} var _ aggregator.Histogram = &Aggregator{} -// New returns a new measure aggregator for computing Histograms. +// New returns a new aggregator for computing Histograms. // // A Histogram observe events and counts them in pre-defined buckets. // And also provides the total sum and count of all observations. diff --git a/sdk/metric/aggregator/histogram/histogram_test.go b/sdk/metric/aggregator/histogram/histogram_test.go index 53aa1250b..6a559cec3 100644 --- a/sdk/metric/aggregator/histogram/histogram_test.go +++ b/sdk/metric/aggregator/histogram/histogram_test.go @@ -84,7 +84,7 @@ func TestHistogramPositiveAndNegative(t *testing.T) { // Validates count, sum and buckets for a given profile and policy func histogram(t *testing.T, profile test.Profile, policy policy) { ctx := context.Background() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg := New(descriptor, boundaries[profile.NumberKind]) @@ -126,7 +126,7 @@ func TestHistogramMerge(t *testing.T) { ctx := context.Background() test.RunProfiles(t, func(t *testing.T, profile test.Profile) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg1 := New(descriptor, boundaries[profile.NumberKind]) agg2 := New(descriptor, boundaries[profile.NumberKind]) @@ -178,7 +178,7 @@ func TestHistogramNotSet(t *testing.T) { ctx := context.Background() test.RunProfiles(t, func(t *testing.T, profile test.Profile) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg := New(descriptor, boundaries[profile.NumberKind]) agg.Checkpoint(ctx, descriptor) diff --git a/sdk/metric/aggregator/minmaxsumcount/mmsc.go b/sdk/metric/aggregator/minmaxsumcount/mmsc.go index 1c840a158..a66bec496 100644 --- a/sdk/metric/aggregator/minmaxsumcount/mmsc.go +++ b/sdk/metric/aggregator/minmaxsumcount/mmsc.go @@ -24,8 +24,8 @@ import ( ) type ( - // Aggregator aggregates measure events, keeping only the min, max, - // sum, and count. + // Aggregator aggregates events that form a distribution, + // keeping only the min, max, sum, and count. Aggregator struct { lock sync.Mutex current state @@ -44,8 +44,9 @@ type ( var _ export.Aggregator = &Aggregator{} var _ aggregator.MinMaxSumCount = &Aggregator{} -// New returns a new measure aggregator for computing min, max, sum, and -// count. It does not compute quantile information other than Min and Max. +// New returns a new aggregator for computing the min, max, sum, and +// count. It does not compute quantile information other than Min and +// Max. // // This type uses a mutex for Update() and Checkpoint() concurrency. func New(desc *metric.Descriptor) *Aggregator { diff --git a/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go b/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go index 50c2fa5fc..d01916b8e 100644 --- a/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go +++ b/sdk/metric/aggregator/minmaxsumcount/mmsc_test.go @@ -79,7 +79,7 @@ func TestMinMaxSumCountPositiveAndNegative(t *testing.T) { // Validates min, max, sum and count for a given profile and policy func minMaxSumCount(t *testing.T, profile test.Profile, policy policy) { ctx := context.Background() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg := New(descriptor) @@ -127,7 +127,7 @@ func TestMinMaxSumCountMerge(t *testing.T) { ctx := context.Background() test.RunProfiles(t, func(t *testing.T, profile test.Profile) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg1 := New(descriptor) agg2 := New(descriptor) @@ -185,7 +185,7 @@ func TestMaxSumCountNotSet(t *testing.T) { ctx := context.Background() test.RunProfiles(t, func(t *testing.T, profile test.Profile) { - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) agg := New(descriptor) agg.Checkpoint(ctx, descriptor) diff --git a/sdk/metric/aggregator/sum/sum_test.go b/sdk/metric/aggregator/sum/sum_test.go index acd37e9ab..617254d2c 100644 --- a/sdk/metric/aggregator/sum/sum_test.go +++ b/sdk/metric/aggregator/sum/sum_test.go @@ -71,13 +71,13 @@ func TestCounterSum(t *testing.T) { }) } -func TestMeasureSum(t *testing.T) { +func TestValueRecorderSum(t *testing.T) { ctx := context.Background() test.RunProfiles(t, func(t *testing.T, profile test.Profile) { agg := New() - descriptor := test.NewAggregatorTest(metric.MeasureKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) sum := metric.Number(0) diff --git a/sdk/metric/benchmark_test.go b/sdk/metric/benchmark_test.go index 9cbc1a578..06c8a980b 100644 --- a/sdk/metric/benchmark_test.go +++ b/sdk/metric/benchmark_test.go @@ -311,7 +311,7 @@ func BenchmarkInt64LastValueAdd(b *testing.B) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewInt64Measure("int64.lastvalue") + mea := fix.meter.NewInt64ValueRecorder("int64.lastvalue") b.ResetTimer() @@ -324,7 +324,7 @@ func BenchmarkInt64LastValueHandleAdd(b *testing.B) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewInt64Measure("int64.lastvalue") + mea := fix.meter.NewInt64ValueRecorder("int64.lastvalue") handle := mea.Bind(labs...) b.ResetTimer() @@ -338,7 +338,7 @@ func BenchmarkFloat64LastValueAdd(b *testing.B) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewFloat64Measure("float64.lastvalue") + mea := fix.meter.NewFloat64ValueRecorder("float64.lastvalue") b.ResetTimer() @@ -351,7 +351,7 @@ func BenchmarkFloat64LastValueHandleAdd(b *testing.B) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewFloat64Measure("float64.lastvalue") + mea := fix.meter.NewFloat64ValueRecorder("float64.lastvalue") handle := mea.Bind(labs...) b.ResetTimer() @@ -361,13 +361,13 @@ func BenchmarkFloat64LastValueHandleAdd(b *testing.B) { } } -// Measures +// ValueRecorders -func benchmarkInt64MeasureAdd(b *testing.B, name string) { +func benchmarkInt64ValueRecorderAdd(b *testing.B, name string) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewInt64Measure(name) + mea := fix.meter.NewInt64ValueRecorder(name) b.ResetTimer() @@ -376,11 +376,11 @@ func benchmarkInt64MeasureAdd(b *testing.B, name string) { } } -func benchmarkInt64MeasureHandleAdd(b *testing.B, name string) { +func benchmarkInt64ValueRecorderHandleAdd(b *testing.B, name string) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewInt64Measure(name) + mea := fix.meter.NewInt64ValueRecorder(name) handle := mea.Bind(labs...) b.ResetTimer() @@ -390,11 +390,11 @@ func benchmarkInt64MeasureHandleAdd(b *testing.B, name string) { } } -func benchmarkFloat64MeasureAdd(b *testing.B, name string) { +func benchmarkFloat64ValueRecorderAdd(b *testing.B, name string) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewFloat64Measure(name) + mea := fix.meter.NewFloat64ValueRecorder(name) b.ResetTimer() @@ -403,11 +403,11 @@ func benchmarkFloat64MeasureAdd(b *testing.B, name string) { } } -func benchmarkFloat64MeasureHandleAdd(b *testing.B, name string) { +func benchmarkFloat64ValueRecorderHandleAdd(b *testing.B, name string) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - mea := fix.meter.NewFloat64Measure(name) + mea := fix.meter.NewFloat64ValueRecorder(name) handle := mea.Bind(labs...) b.ResetTimer() @@ -467,55 +467,55 @@ func BenchmarkObserverObservationFloat64(b *testing.B) { // MaxSumCount func BenchmarkInt64MaxSumCountAdd(b *testing.B) { - benchmarkInt64MeasureAdd(b, "int64.minmaxsumcount") + benchmarkInt64ValueRecorderAdd(b, "int64.minmaxsumcount") } func BenchmarkInt64MaxSumCountHandleAdd(b *testing.B) { - benchmarkInt64MeasureHandleAdd(b, "int64.minmaxsumcount") + benchmarkInt64ValueRecorderHandleAdd(b, "int64.minmaxsumcount") } func BenchmarkFloat64MaxSumCountAdd(b *testing.B) { - benchmarkFloat64MeasureAdd(b, "float64.minmaxsumcount") + benchmarkFloat64ValueRecorderAdd(b, "float64.minmaxsumcount") } func BenchmarkFloat64MaxSumCountHandleAdd(b *testing.B) { - benchmarkFloat64MeasureHandleAdd(b, "float64.minmaxsumcount") + benchmarkFloat64ValueRecorderHandleAdd(b, "float64.minmaxsumcount") } // DDSketch func BenchmarkInt64DDSketchAdd(b *testing.B) { - benchmarkInt64MeasureAdd(b, "int64.ddsketch") + benchmarkInt64ValueRecorderAdd(b, "int64.ddsketch") } func BenchmarkInt64DDSketchHandleAdd(b *testing.B) { - benchmarkInt64MeasureHandleAdd(b, "int64.ddsketch") + benchmarkInt64ValueRecorderHandleAdd(b, "int64.ddsketch") } func BenchmarkFloat64DDSketchAdd(b *testing.B) { - benchmarkFloat64MeasureAdd(b, "float64.ddsketch") + benchmarkFloat64ValueRecorderAdd(b, "float64.ddsketch") } func BenchmarkFloat64DDSketchHandleAdd(b *testing.B) { - benchmarkFloat64MeasureHandleAdd(b, "float64.ddsketch") + benchmarkFloat64ValueRecorderHandleAdd(b, "float64.ddsketch") } // Array func BenchmarkInt64ArrayAdd(b *testing.B) { - benchmarkInt64MeasureAdd(b, "int64.array") + benchmarkInt64ValueRecorderAdd(b, "int64.array") } func BenchmarkInt64ArrayHandleAdd(b *testing.B) { - benchmarkInt64MeasureHandleAdd(b, "int64.array") + benchmarkInt64ValueRecorderHandleAdd(b, "int64.array") } func BenchmarkFloat64ArrayAdd(b *testing.B) { - benchmarkFloat64MeasureAdd(b, "float64.array") + benchmarkFloat64ValueRecorderAdd(b, "float64.array") } func BenchmarkFloat64ArrayHandleAdd(b *testing.B) { - benchmarkFloat64MeasureHandleAdd(b, "float64.array") + benchmarkFloat64ValueRecorderHandleAdd(b, "float64.array") } // BatchRecord diff --git a/sdk/metric/correct_test.go b/sdk/metric/correct_test.go index 02174b877..e26aa630a 100644 --- a/sdk/metric/correct_test.go +++ b/sdk/metric/correct_test.go @@ -107,7 +107,7 @@ func TestInputRangeTestCounter(t *testing.T) { require.Nil(t, sdkErr) } -func TestInputRangeTestMeasure(t *testing.T) { +func TestInputRangeTestValueRecorder(t *testing.T) { ctx := context.Background() integrator := &correctnessIntegrator{ t: t, @@ -120,17 +120,17 @@ func TestInputRangeTestMeasure(t *testing.T) { sdkErr = handleErr }) - measure := Must(meter).NewFloat64Measure("name.measure") + valuerecorder := Must(meter).NewFloat64ValueRecorder("name.valuerecorder") - measure.Record(ctx, math.NaN()) + valuerecorder.Record(ctx, math.NaN()) require.Equal(t, aggregator.ErrNaNInput, sdkErr) sdkErr = nil checkpointed := sdk.Collect(ctx) require.Equal(t, 0, checkpointed) - measure.Record(ctx, 1) - measure.Record(ctx, 2) + valuerecorder.Record(ctx, 1) + valuerecorder.Record(ctx, 2) integrator.records = nil checkpointed = sdk.Collect(ctx) @@ -150,9 +150,9 @@ func TestDisabledInstrument(t *testing.T) { sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") - measure := Must(meter).NewFloat64Measure("name.disabled") + valuerecorder := Must(meter).NewFloat64ValueRecorder("name.disabled") - measure.Record(ctx, -1) + valuerecorder.Record(ctx, -1) checkpointed := sdk.Collect(ctx) require.Equal(t, 0, checkpointed) @@ -389,8 +389,8 @@ func TestRecordBatch(t *testing.T) { counter1 := Must(meter).NewInt64Counter("int64.counter") counter2 := Must(meter).NewFloat64Counter("float64.counter") - measure1 := Must(meter).NewInt64Measure("int64.measure") - measure2 := Must(meter).NewFloat64Measure("float64.measure") + valuerecorder1 := Must(meter).NewInt64ValueRecorder("int64.valuerecorder") + valuerecorder2 := Must(meter).NewFloat64ValueRecorder("float64.valuerecorder") sdk.RecordBatch( ctx, @@ -400,8 +400,8 @@ func TestRecordBatch(t *testing.T) { }, counter1.Measurement(1), counter2.Measurement(2), - measure1.Measurement(3), - measure2.Measurement(4), + valuerecorder1.Measurement(3), + valuerecorder2.Measurement(4), ) sdk.Collect(ctx) @@ -411,10 +411,10 @@ func TestRecordBatch(t *testing.T) { _ = out.AddTo(rec) } require.EqualValues(t, map[string]float64{ - "int64.counter/A=B,C=D": 1, - "float64.counter/A=B,C=D": 2, - "int64.measure/A=B,C=D": 3, - "float64.measure/A=B,C=D": 4, + "int64.counter/A=B,C=D": 1, + "float64.counter/A=B,C=D": 2, + "int64.valuerecorder/A=B,C=D": 3, + "float64.valuerecorder/A=B,C=D": 4, }, out.Map) } diff --git a/sdk/metric/doc.go b/sdk/metric/doc.go index cee67d00b..1ad5edc7d 100644 --- a/sdk/metric/doc.go +++ b/sdk/metric/doc.go @@ -13,57 +13,34 @@ // limitations under the License. /* -Package metric implements the OpenTelemetry metric.Meter API. The SDK -supports configurable metrics export behavior through a collection of -export interfaces that support various export strategies, described below. +Package metric implements the OpenTelemetry metric.MeterImpl +interface. The Accumulator type supports configurable metrics export +behavior through a collection of export interfaces that support +various export strategies, described below. -The metric.Meter API consists of methods for constructing each of the basic -kinds of metric instrument. There are six types of instrument available to -the end user, comprised of three basic kinds of metric instrument (Counter, -Measure, Observer) crossed with two kinds of number (int64, float64). +The metric.MeterImpl API consists of methods for constructing +synchronous and asynchronous instruments. There are two constructors +per instrument for the two kinds of number (int64, float64). -The API assists the SDK by consolidating the variety of metric instruments -into a narrower interface, allowing the SDK to avoid repetition of -boilerplate. The API and SDK are separated such that an event reaching -the SDK has a uniform structure: an instrument, a label set, and a -numerical value. +Synchronous instruments are managed by a sync.Map containing a *record +with the current state for each synchronous instrument. A bound +instrument encapsulates a direct pointer to the record, allowing +bound metric events to bypass a sync.Map lookup. A lock-free +algorithm is used to protect against races when adding and removing +items from the sync.Map. -To this end, the API uses a kv.Number type to represent either an int64 -or a float64, depending on the instrument's definition. A single -implementation interface is used for counter and measure instruments, -metric.InstrumentImpl, and a single implementation interface is used for -their handles, metric.HandleImpl. For observers, the API defines -interfaces, for which the SDK provides an implementation. - -There are four entry points for events in the Metrics API - three for -synchronous instruments (counters and measures) and one for asynchronous -instruments (observers). The entry points for synchronous instruments are: -via instrument handles, via direct instrument calls, and via BatchRecord. -The SDK is designed with handles as the primary entry point, the other two -entry points are implemented in terms of short-lived handles. For example, -the implementation of a direct call allocates a handle, operates on the -handle, and releases the handle. Similarly, the implementation of -RecordBatch uses a short-lived handle for each measurement in the batch. -The entry point for asynchronous instruments is via observer callbacks. -Observer callbacks behave like a set of instrument handles - one for each -observation for a distinct label set. The observer handles are alive as -long as they are used. If the callback stops reporting values for a -certain label set, the associated handle is dropped. +Asynchronous instruments are managed by an internal +AsyncInstrumentState, which coordinates calling batch and single +instrument callbacks. Internal Structure -The SDK is designed with minimal use of locking, to avoid adding -contention for user-level code. For each handle, whether it is held by -user-level code or a short-lived device, there exists an internal record -managed by the SDK. Each internal record corresponds to a specific -instrument and label set combination. - Each observer also has its own kind of record stored in the SDK. This record contains a set of recorders for every specific label set used in the callback. A sync.Map maintains the mapping of current instruments and label sets to -internal records. To create a new handle, the SDK consults the Map to +internal records. To create a new bound instrument, the SDK consults the Map to locate an existing record, otherwise it constructs a new record. The SDK maintains a count of the number of references to each record, ensuring that records are not reclaimed from the Map while they are still active @@ -74,12 +51,7 @@ sweeps through all records in the SDK, checkpointing their state. When a record is discovered that has no references and has not been updated since the prior collection pass, it is removed from the Map. -The SDK maintains a current epoch number, corresponding to the number of -completed collections. Each recorder of an observer record contains the -last epoch during which it was updated. This variable allows the collection -code path to detect stale recorders and remove them. - -Each record of a handle and recorder of an observer has an associated +Both synchronous and asynchronous instruments have an associated aggregator, which maintains the current state resulting from all metric events since its last checkpoint. Aggregators may be lock-free or they may use locking, but they should expect to be called concurrently. Aggregators @@ -97,21 +69,18 @@ enters the SDK resulting in a new record, and collection context, where a system-level thread performs a collection pass through the SDK. -Descriptor is a struct that describes the metric instrument to the export -pipeline, containing the name, recommended aggregation keys, units, -description, metric kind (counter or measure), number kind (int64 or -float64), and whether the instrument has alternate semantics or not (i.e., -monotonic=false counter, absolute=false measure). A Descriptor accompanies -metric data as it passes through the export pipeline. +Descriptor is a struct that describes the metric instrument to the +export pipeline, containing the name, units, description, metric kind, +number kind (int64 or float64). A Descriptor accompanies metric data +as it passes through the export pipeline. The AggregationSelector interface supports choosing the method of aggregation to apply to a particular instrument. Given the Descriptor, this AggregatorFor method returns an implementation of Aggregator. If this interface returns nil, the metric will be disabled. The aggregator should be matched to the capabilities of the exporter. Selecting the aggregator -for counter instruments is relatively straightforward, but for measure and -observer instruments there are numerous choices with different cost and -quality tradeoffs. +for sum-only instruments is relatively straightforward, but many options +are available for aggregating distributions from ValueRecorder instruments. Aggregator is an interface which implements a concrete strategy for aggregating metric updates. Several Aggregator implementations are diff --git a/sdk/metric/histogram_stress_test.go b/sdk/metric/histogram_stress_test.go index 4a40823ef..d05536622 100644 --- a/sdk/metric/histogram_stress_test.go +++ b/sdk/metric/histogram_stress_test.go @@ -25,7 +25,7 @@ import ( ) func TestStressInt64Histogram(t *testing.T) { - desc := metric.NewDescriptor("some_metric", metric.MeasureKind, metric.Int64NumberKind) + desc := metric.NewDescriptor("some_metric", metric.ValueRecorderKind, metric.Int64NumberKind) h := histogram.New(&desc, []metric.Number{metric.NewInt64Number(25), metric.NewInt64Number(50), metric.NewInt64Number(75)}) ctx, cancelFunc := context.WithCancel(context.Background()) diff --git a/sdk/metric/minmaxsumcount_stress_test.go b/sdk/metric/minmaxsumcount_stress_test.go index ecec40564..0b51f66a6 100644 --- a/sdk/metric/minmaxsumcount_stress_test.go +++ b/sdk/metric/minmaxsumcount_stress_test.go @@ -25,7 +25,7 @@ import ( ) func TestStressInt64MinMaxSumCount(t *testing.T) { - desc := metric.NewDescriptor("some_metric", metric.MeasureKind, metric.Int64NumberKind) + desc := metric.NewDescriptor("some_metric", metric.ValueRecorderKind, metric.Int64NumberKind) mmsc := minmaxsumcount.New(&desc) ctx, cancel := context.WithCancel(context.Background()) diff --git a/sdk/metric/selector/simple/simple.go b/sdk/metric/selector/simple/simple.go index e8929f093..3f7517585 100644 --- a/sdk/metric/selector/simple/simple.go +++ b/sdk/metric/selector/simple/simple.go @@ -42,40 +42,40 @@ var ( _ export.AggregationSelector = selectorHistogram{} ) -// NewWithInexpensiveMeasure returns a simple aggregation selector +// NewWithInexpensiveDistribution returns a simple aggregation selector // that uses counter, minmaxsumcount and minmaxsumcount aggregators // for the three kinds of metric. This selector is faster and uses // less memory than the others because minmaxsumcount does not // aggregate quantile information. -func NewWithInexpensiveMeasure() export.AggregationSelector { +func NewWithInexpensiveDistribution() export.AggregationSelector { return selectorInexpensive{} } -// NewWithSketchMeasure returns a simple aggregation selector that +// NewWithSketchDistribution returns a simple aggregation selector that // uses counter, ddsketch, and ddsketch aggregators for the three // kinds of metric. This selector uses more cpu and memory than the -// NewWithInexpensiveMeasure because it uses one DDSketch per distinct -// measure/observer and labelset. -func NewWithSketchMeasure(config *ddsketch.Config) export.AggregationSelector { +// NewWithInexpensiveDistribution because it uses one DDSketch per distinct +// instrument and label set. +func NewWithSketchDistribution(config *ddsketch.Config) export.AggregationSelector { return selectorSketch{ config: config, } } -// NewWithExactMeasure returns a simple aggregation selector that uses +// NewWithExactDistribution returns a simple aggregation selector that uses // counter, array, and array aggregators for the three kinds of metric. -// This selector uses more memory than the NewWithSketchMeasure +// This selector uses more memory than the NewWithSketchDistribution // because it aggregates an array of all values, therefore is able to // compute exact quantiles. -func NewWithExactMeasure() export.AggregationSelector { +func NewWithExactDistribution() export.AggregationSelector { return selectorExact{} } -// NewWithHistogramMeasure returns a simple aggregation selector that uses counter, +// NewWithHistogramDistribution returns a simple aggregation selector that uses counter, // histogram, and histogram aggregators for the three kinds of metric. This -// selector uses more memory than the NewWithInexpensiveMeasure because it +// selector uses more memory than the NewWithInexpensiveDistribution because it // uses a counter per bucket. -func NewWithHistogramMeasure(boundaries []metric.Number) export.AggregationSelector { +func NewWithHistogramDistribution(boundaries []metric.Number) export.AggregationSelector { return selectorHistogram{boundaries: boundaries} } @@ -83,7 +83,7 @@ func (selectorInexpensive) AggregatorFor(descriptor *metric.Descriptor) export.A switch descriptor.MetricKind() { case metric.ObserverKind: fallthrough - case metric.MeasureKind: + case metric.ValueRecorderKind: return minmaxsumcount.New(descriptor) default: return sum.New() @@ -94,7 +94,7 @@ func (s selectorSketch) AggregatorFor(descriptor *metric.Descriptor) export.Aggr switch descriptor.MetricKind() { case metric.ObserverKind: fallthrough - case metric.MeasureKind: + case metric.ValueRecorderKind: return ddsketch.New(s.config, descriptor) default: return sum.New() @@ -105,7 +105,7 @@ func (selectorExact) AggregatorFor(descriptor *metric.Descriptor) export.Aggrega switch descriptor.MetricKind() { case metric.ObserverKind: fallthrough - case metric.MeasureKind: + case metric.ValueRecorderKind: return array.New() default: return sum.New() @@ -116,7 +116,7 @@ func (s selectorHistogram) AggregatorFor(descriptor *metric.Descriptor) export.A switch descriptor.MetricKind() { case metric.ObserverKind: fallthrough - case metric.MeasureKind: + case metric.ValueRecorderKind: return histogram.New(descriptor, s.boundaries) default: return sum.New() diff --git a/sdk/metric/selector/simple/simple_test.go b/sdk/metric/selector/simple/simple_test.go index 0f79df535..a80c62ac2 100644 --- a/sdk/metric/selector/simple/simple_test.go +++ b/sdk/metric/selector/simple/simple_test.go @@ -29,35 +29,35 @@ import ( ) var ( - testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, metric.Int64NumberKind) - testMeasureDesc = metric.NewDescriptor("measure", metric.MeasureKind, metric.Int64NumberKind) - testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, metric.Int64NumberKind) + testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, metric.Int64NumberKind) + testValueRecorderDesc = metric.NewDescriptor("valuerecorder", metric.ValueRecorderKind, metric.Int64NumberKind) + testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, metric.Int64NumberKind) ) -func TestInexpensiveMeasure(t *testing.T) { - inex := simple.NewWithInexpensiveMeasure() +func TestInexpensiveDistribution(t *testing.T) { + inex := simple.NewWithInexpensiveDistribution() require.NotPanics(t, func() { _ = inex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) - require.NotPanics(t, func() { _ = inex.AggregatorFor(&testMeasureDesc).(*minmaxsumcount.Aggregator) }) + require.NotPanics(t, func() { _ = inex.AggregatorFor(&testValueRecorderDesc).(*minmaxsumcount.Aggregator) }) require.NotPanics(t, func() { _ = inex.AggregatorFor(&testObserverDesc).(*minmaxsumcount.Aggregator) }) } -func TestSketchMeasure(t *testing.T) { - sk := simple.NewWithSketchMeasure(ddsketch.NewDefaultConfig()) +func TestSketchDistribution(t *testing.T) { + sk := simple.NewWithSketchDistribution(ddsketch.NewDefaultConfig()) require.NotPanics(t, func() { _ = sk.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) - require.NotPanics(t, func() { _ = sk.AggregatorFor(&testMeasureDesc).(*ddsketch.Aggregator) }) + require.NotPanics(t, func() { _ = sk.AggregatorFor(&testValueRecorderDesc).(*ddsketch.Aggregator) }) require.NotPanics(t, func() { _ = sk.AggregatorFor(&testObserverDesc).(*ddsketch.Aggregator) }) } -func TestExactMeasure(t *testing.T) { - ex := simple.NewWithExactMeasure() +func TestExactDistribution(t *testing.T) { + ex := simple.NewWithExactDistribution() require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) - require.NotPanics(t, func() { _ = ex.AggregatorFor(&testMeasureDesc).(*array.Aggregator) }) + require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueRecorderDesc).(*array.Aggregator) }) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*array.Aggregator) }) } -func TestHistogramMeasure(t *testing.T) { - ex := simple.NewWithHistogramMeasure([]metric.Number{}) +func TestHistogramDistribution(t *testing.T) { + ex := simple.NewWithHistogramDistribution([]metric.Number{}) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) - require.NotPanics(t, func() { _ = ex.AggregatorFor(&testMeasureDesc).(*histogram.Aggregator) }) + require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueRecorderDesc).(*histogram.Aggregator) }) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*histogram.Aggregator) }) } diff --git a/sdk/metric/stress_test.go b/sdk/metric/stress_test.go index 7e15e1594..7bdd72432 100644 --- a/sdk/metric/stress_test.go +++ b/sdk/metric/stress_test.go @@ -285,7 +285,7 @@ func (f *testFixture) Process(_ context.Context, record export.Record) error { f.T.Fatal("Sum error: ", err) } f.impl.storeCollect(actual, sum, time.Time{}) - case metric.MeasureKind: + case metric.ValueRecorderKind: lv, ts, err := agg.(aggregator.LastValue).LastValue() if err != nil && err != aggregator.ErrNoData { f.T.Fatal("Last value error: ", err) @@ -431,15 +431,15 @@ func TestStressFloat64Counter(t *testing.T) { func intLastValueTestImpl() testImpl { return testImpl{ newInstrument: func(meter api.Meter, name string) SyncImpler { - return Must(meter).NewInt64Measure(name + ".lastvalue") + return Must(meter).NewInt64ValueRecorder(name + ".lastvalue") }, getUpdateValue: func() api.Number { r1 := rand.Int63() return api.NewInt64Number(rand.Int63() - r1) }, operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) { - measure := inst.(api.Int64Measure) - measure.Record(ctx, value.AsInt64(), labels...) + valuerecorder := inst.(api.Int64ValueRecorder) + valuerecorder.Record(ctx, value.AsInt64(), labels...) }, newStore: func() interface{} { return &lastValueState{ @@ -473,14 +473,14 @@ func TestStressInt64LastValue(t *testing.T) { func floatLastValueTestImpl() testImpl { return testImpl{ newInstrument: func(meter api.Meter, name string) SyncImpler { - return Must(meter).NewFloat64Measure(name + ".lastvalue") + return Must(meter).NewFloat64ValueRecorder(name + ".lastvalue") }, getUpdateValue: func() api.Number { return api.NewFloat64Number((-0.5 + rand.Float64()) * 100000) }, operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) { - measure := inst.(api.Float64Measure) - measure.Record(ctx, value.AsFloat64(), labels...) + valuerecorder := inst.(api.Float64ValueRecorder) + valuerecorder.Record(ctx, value.AsFloat64(), labels...) }, newStore: func() interface{} { return &lastValueState{ From 2dee67652aec812903a6db53945f5c8a54d6cc47 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 18 May 2020 09:44:33 -0700 Subject: [PATCH 19/21] Histogram aggregator initial state (fix #735) (#736) * Add a test * Add comments and description options * Another test * Undo buffer re-use * Mod tidy * Precommit * Again * Copyright * Undo rename --- exporters/metric/prometheus/example_test.go | 97 +++++++++++++++++++ sdk/metric/aggregator/histogram/histogram.go | 43 ++++---- .../aggregator/histogram/histogram_test.go | 29 ++++-- 3 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 exporters/metric/prometheus/example_test.go diff --git a/exporters/metric/prometheus/example_test.go b/exporters/metric/prometheus/example_test.go new file mode 100644 index 000000000..81e741a38 --- /dev/null +++ b/exporters/metric/prometheus/example_test.go @@ -0,0 +1,97 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus_test + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + + "go.opentelemetry.io/otel/api/kv" + "go.opentelemetry.io/otel/api/metric" + "go.opentelemetry.io/otel/exporters/metric/prometheus" + sdk "go.opentelemetry.io/otel/sdk/metric" + integrator "go.opentelemetry.io/otel/sdk/metric/integrator/simple" + "go.opentelemetry.io/otel/sdk/metric/selector/simple" +) + +// This test demonstrates that it is relatively difficult to setup a +// Prometheus export pipeline: +// +// 1. The default boundaries are difficult to pass, should be []float instead of []metric.Number +// 2. The push controller doesn't make sense b/c Prometheus is pull-bsaed +// +// TODO: Address these issues; add Resources to the test. + +func ExampleNewExportPipeline() { + // Create a meter + selector := simple.NewWithHistogramDistribution(nil) + exporter, err := prometheus.NewRawExporter(prometheus.Config{}) + if err != nil { + panic(err) + } + integrator := integrator.New(selector, true) + meterImpl := sdk.NewAccumulator(integrator) + meter := metric.WrapMeterImpl(meterImpl, "example") + + ctx := context.Background() + + // Use two instruments + counter := metric.Must(meter).NewInt64Counter( + "a.counter", + metric.WithDescription("Counts things"), + ) + recorder := metric.Must(meter).NewInt64ValueRecorder( + "a.valuerecorder", + metric.WithDescription("Records values"), + ) + + counter.Add(ctx, 100, kv.String("key", "value")) + recorder.Record(ctx, 100, kv.String("key", "value")) + + // Simulate a push + meterImpl.Collect(ctx) + err = exporter.Export(ctx, nil, integrator.CheckpointSet()) + if err != nil { + panic(err) + } + + // GET the HTTP endpoint + var input bytes.Buffer + resp := httptest.NewRecorder() + req, err := http.NewRequest("GET", "/", &input) + if err != nil { + panic(err) + } + exporter.ServeHTTP(resp, req) + data, err := ioutil.ReadAll(resp.Result().Body) + if err != nil { + panic(err) + } + fmt.Print(string(data)) + + // Output: + // # HELP a_counter Counts things + // # TYPE a_counter counter + // a_counter{key="value"} 100 + // # HELP a_valuerecorder Records values + // # TYPE a_valuerecorder histogram + // a_valuerecorder_bucket{key="value",le="+Inf"} 1 + // a_valuerecorder_sum{key="value"} 100 + // a_valuerecorder_count{key="value"} 1 +} diff --git a/sdk/metric/aggregator/histogram/histogram.go b/sdk/metric/aggregator/histogram/histogram.go index 6566dab91..ccb0c2d3c 100644 --- a/sdk/metric/aggregator/histogram/histogram.go +++ b/sdk/metric/aggregator/histogram/histogram.go @@ -24,6 +24,11 @@ import ( "go.opentelemetry.io/otel/sdk/export/metric/aggregator" ) +// Note: This code uses a Mutex to govern access to the exclusive +// aggregator state. This is in contrast to a lock-free approach +// (as in the Go prometheus client) that was reverted here: +// https://github.com/open-telemetry/opentelemetry-go/pull/669 + type ( // Aggregator observe events and counts them in pre-determined buckets. // It also calculates the sum and count of all events. @@ -39,10 +44,9 @@ type ( // the sum and counts for all observed values and // the less than equal bucket count for the pre-determined boundaries. state struct { - // all fields have to be aligned for 64-bit atomic operations. - buckets aggregator.Buckets - count metric.Number - sum metric.Number + bucketCounts []metric.Number + count metric.Number + sum metric.Number } ) @@ -71,17 +75,12 @@ func New(desc *metric.Descriptor, boundaries []metric.Number) *Aggregator { sort.Sort(&sortedBoundaries) boundaries = sortedBoundaries.numbers - agg := Aggregator{ + return &Aggregator{ kind: desc.NumberKind(), boundaries: boundaries, - current: state{ - buckets: aggregator.Buckets{ - Boundaries: boundaries, - Counts: make([]metric.Number, len(boundaries)+1), - }, - }, + current: emptyState(boundaries), + checkpoint: emptyState(boundaries), } - return &agg } // Sum returns the sum of all values in the checkpoint. @@ -102,7 +101,10 @@ func (c *Aggregator) Count() (int64, error) { func (c *Aggregator) Histogram() (aggregator.Buckets, error) { c.lock.Lock() defer c.lock.Unlock() - return c.checkpoint.buckets, nil + return aggregator.Buckets{ + Boundaries: c.boundaries, + Counts: c.checkpoint.bucketCounts, + }, nil } // Checkpoint saves the current state and resets the current state to @@ -111,16 +113,13 @@ func (c *Aggregator) Histogram() (aggregator.Buckets, error) { // other. func (c *Aggregator) Checkpoint(ctx context.Context, desc *metric.Descriptor) { c.lock.Lock() - c.checkpoint, c.current = c.current, c.emptyState() + c.checkpoint, c.current = c.current, emptyState(c.boundaries) c.lock.Unlock() } -func (c *Aggregator) emptyState() state { +func emptyState(boundaries []metric.Number) state { return state{ - buckets: aggregator.Buckets{ - Boundaries: c.boundaries, - Counts: make([]metric.Number, len(c.boundaries)+1), - }, + bucketCounts: make([]metric.Number, len(boundaries)+1), } } @@ -141,7 +140,7 @@ func (c *Aggregator) Update(_ context.Context, number metric.Number, desc *metri c.current.count.AddInt64(1) c.current.sum.AddNumber(kind, number) - c.current.buckets.Counts[bucketID].AddUint64(1) + c.current.bucketCounts[bucketID].AddUint64(1) return nil } @@ -156,8 +155,8 @@ func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error c.checkpoint.sum.AddNumber(desc.NumberKind(), o.checkpoint.sum) c.checkpoint.count.AddNumber(metric.Uint64NumberKind, o.checkpoint.count) - for i := 0; i < len(c.checkpoint.buckets.Counts); i++ { - c.checkpoint.buckets.Counts[i].AddNumber(metric.Uint64NumberKind, o.checkpoint.buckets.Counts[i]) + for i := 0; i < len(c.checkpoint.bucketCounts); i++ { + c.checkpoint.bucketCounts[i].AddNumber(metric.Uint64NumberKind, o.checkpoint.bucketCounts[i]) } return nil } diff --git a/sdk/metric/aggregator/histogram/histogram_test.go b/sdk/metric/aggregator/histogram/histogram_test.go index 6a559cec3..c1541ee2b 100644 --- a/sdk/metric/aggregator/histogram/histogram_test.go +++ b/sdk/metric/aggregator/histogram/histogram_test.go @@ -113,15 +113,28 @@ func histogram(t *testing.T, profile test.Profile, policy policy) { require.Equal(t, all.Count(), count, "Same count -"+policy.name) require.Nil(t, err) - require.Equal(t, len(agg.checkpoint.buckets.Counts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries") + require.Equal(t, len(agg.checkpoint.bucketCounts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries") counts := calcBuckets(all.Points(), profile) for i, v := range counts { - bCount := agg.checkpoint.buckets.Counts[i].AsUint64() - require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg.checkpoint.buckets.Counts) + bCount := agg.checkpoint.bucketCounts[i].AsUint64() + require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg.checkpoint.bucketCounts) } } +func TestHistogramInitial(t *testing.T) { + test.RunProfiles(t, func(t *testing.T, profile test.Profile) { + descriptor := test.NewAggregatorTest(metric.ValueRecorderKind, profile.NumberKind) + + agg := New(descriptor, boundaries[profile.NumberKind]) + buckets, err := agg.Histogram() + + require.NoError(t, err) + require.Equal(t, len(buckets.Counts), len(boundaries[profile.NumberKind])+1) + require.Equal(t, len(buckets.Boundaries), len(boundaries[profile.NumberKind])) + }) +} + func TestHistogramMerge(t *testing.T) { ctx := context.Background() @@ -164,12 +177,12 @@ func TestHistogramMerge(t *testing.T) { require.Equal(t, all.Count(), count, "Same count - absolute") require.Nil(t, err) - require.Equal(t, len(agg1.checkpoint.buckets.Counts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries") + require.Equal(t, len(agg1.checkpoint.bucketCounts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries") counts := calcBuckets(all.Points(), profile) for i, v := range counts { - bCount := agg1.checkpoint.buckets.Counts[i].AsUint64() - require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg1.checkpoint.buckets.Counts) + bCount := agg1.checkpoint.bucketCounts[i].AsUint64() + require.Equal(t, v, bCount, "Wrong bucket #%d count: %v != %v", i, counts, agg1.checkpoint.bucketCounts) } }) } @@ -191,8 +204,8 @@ func TestHistogramNotSet(t *testing.T) { require.Equal(t, int64(0), count, "Empty checkpoint count = 0") require.Nil(t, err) - require.Equal(t, len(agg.checkpoint.buckets.Counts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries") - for i, bCount := range agg.checkpoint.buckets.Counts { + require.Equal(t, len(agg.checkpoint.bucketCounts), len(boundaries[profile.NumberKind])+1, "There should be b + 1 counts, where b is the number of boundaries") + for i, bCount := range agg.checkpoint.bucketCounts { require.Equal(t, uint64(0), bCount.AsUint64(), "Bucket #%d must have 0 observed values", i) } }) From 76baa9cc7a46280f0bbc3721adc19556bda053fe Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 18 May 2020 10:48:58 -0700 Subject: [PATCH 20/21] Remove the push controller named Meter map (#738) * Remove the push controller named Meter map * Checkpoint * Remove Provider impls * Add a test * Expose Provider() getter instead of implementing the interface --- api/global/internal/meter_test.go | 2 +- api/metric/registry/registry.go | 20 +++++++++++++++++ api/metric/registry/registry_test.go | 11 ++++++++++ exporters/metric/prometheus/prometheus.go | 2 +- exporters/metric/stdout/example_test.go | 2 +- exporters/metric/stdout/stdout.go | 2 +- exporters/otlp/otlp_integration_test.go | 2 +- internal/metric/mock.go | 26 +---------------------- sdk/metric/controller/push/push.go | 26 ++++++----------------- sdk/metric/controller/push/push_test.go | 4 ++-- sdk/metric/example_test.go | 2 +- 11 files changed, 47 insertions(+), 52 deletions(-) diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 17485b745..5c436791d 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -407,7 +407,7 @@ func TestRecordBatchRealSDK(t *testing.T) { if err != nil { t.Fatal(err) } - global.SetMeterProvider(pusher) + global.SetMeterProvider(pusher.Provider()) meter.RecordBatch(context.Background(), nil, counter.Measurement(1)) pusher.Stop() diff --git a/api/metric/registry/registry.go b/api/metric/registry/registry.go index 3a66b6903..56b187861 100644 --- a/api/metric/registry/registry.go +++ b/api/metric/registry/registry.go @@ -23,6 +23,13 @@ import ( "go.opentelemetry.io/otel/api/metric" ) +// Provider is a standard metric.Provider for wrapping `MeterImpl` +type Provider struct { + impl metric.MeterImpl +} + +var _ metric.Provider = (*Provider)(nil) + // uniqueInstrumentMeterImpl implements the metric.MeterImpl interface, adding // uniqueness checking for instrument descriptors. Use NewUniqueInstrumentMeter // to wrap an implementation with uniqueness checking. @@ -39,6 +46,19 @@ type key struct { libraryName string } +// NewProvider returns a new provider that implements instrument +// name-uniqueness checking. +func NewProvider(impl metric.MeterImpl) *Provider { + return &Provider{ + impl: NewUniqueInstrumentMeterImpl(impl), + } +} + +// Meter implements metric.Provider. +func (p *Provider) Meter(name string) metric.Meter { + return metric.WrapMeterImpl(p.impl, name) +} + // ErrMetricKindMismatch is the standard error for mismatched metric // instrument definitions. var ErrMetricKindMismatch = fmt.Errorf( diff --git a/api/metric/registry/registry_test.go b/api/metric/registry/registry_test.go index 51f8392a1..3d5991ca8 100644 --- a/api/metric/registry/registry_test.go +++ b/api/metric/registry/registry_test.go @@ -118,3 +118,14 @@ func TestRegistryDiffInstruments(t *testing.T) { } } } + +func TestProvider(t *testing.T) { + impl, _ := mockTest.NewMeter() + p := registry.NewProvider(impl) + m1 := p.Meter("m1") + m1p := p.Meter("m1") + m2 := p.Meter("m2") + + require.Equal(t, m1, m1p) + require.NotEqual(t, m1, m2) +} diff --git a/exporters/metric/prometheus/prometheus.go b/exporters/metric/prometheus/prometheus.go index 5af88a6b7..4d615fdf4 100644 --- a/exporters/metric/prometheus/prometheus.go +++ b/exporters/metric/prometheus/prometheus.go @@ -140,7 +140,7 @@ func InstallNewPipeline(config Config) (*push.Controller, http.HandlerFunc, erro if err != nil { return controller, hf, err } - global.SetMeterProvider(controller) + global.SetMeterProvider(controller.Provider()) return controller, hf, err } diff --git a/exporters/metric/stdout/example_test.go b/exporters/metric/stdout/example_test.go index 9cb3b45ad..0952b41c9 100644 --- a/exporters/metric/stdout/example_test.go +++ b/exporters/metric/stdout/example_test.go @@ -38,7 +38,7 @@ func ExampleNewExportPipeline() { ctx := context.Background() key := kv.Key("key") - meter := pusher.Meter("example") + meter := pusher.Provider().Meter("example") // Create and update a single counter: counter := metric.Must(meter).NewInt64Counter("a.counter") diff --git a/exporters/metric/stdout/stdout.go b/exporters/metric/stdout/stdout.go index d22b5f070..5e8b513a5 100644 --- a/exporters/metric/stdout/stdout.go +++ b/exporters/metric/stdout/stdout.go @@ -126,7 +126,7 @@ func InstallNewPipeline(config Config, opts ...push.Option) (*push.Controller, e if err != nil { return controller, err } - global.SetMeterProvider(controller) + global.SetMeterProvider(controller.Provider()) return controller, err } diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go index 624bd4a07..54aae4f0c 100644 --- a/exporters/otlp/otlp_integration_test.go +++ b/exporters/otlp/otlp_integration_test.go @@ -115,7 +115,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) pusher.Start() ctx := context.Background() - meter := pusher.Meter("test-meter") + meter := pusher.Provider().Meter("test-meter") labels := []kv.KeyValue{kv.Bool("test", true)} type data struct { diff --git a/internal/metric/mock.go b/internal/metric/mock.go index 4ec328585..985ea7fc0 100644 --- a/internal/metric/mock.go +++ b/internal/metric/mock.go @@ -38,13 +38,6 @@ type ( LibraryName string } - MeterProvider struct { - lock sync.Mutex - impl *MeterImpl - unique metric.MeterImpl - registered map[string]apimetric.Meter - } - MeterImpl struct { lock sync.Mutex @@ -123,24 +116,7 @@ func NewProvider() (*MeterImpl, apimetric.Provider) { impl := &MeterImpl{ asyncInstruments: NewAsyncInstrumentState(nil), } - p := &MeterProvider{ - impl: impl, - unique: registry.NewUniqueInstrumentMeterImpl(impl), - registered: map[string]apimetric.Meter{}, - } - return impl, p -} - -func (p *MeterProvider) Meter(name string) apimetric.Meter { - p.lock.Lock() - defer p.lock.Unlock() - - if lookup, ok := p.registered[name]; ok { - return lookup - } - m := apimetric.WrapMeterImpl(p.unique, name) - p.registered[name] = m - return m + return impl, registry.NewProvider(impl) } func NewMeter() (*MeterImpl, apimetric.Meter) { diff --git a/sdk/metric/controller/push/push.go b/sdk/metric/controller/push/push.go index d93d032de..0e00ce5fd 100644 --- a/sdk/metric/controller/push/push.go +++ b/sdk/metric/controller/push/push.go @@ -32,8 +32,6 @@ type Controller struct { collectLock sync.Mutex accumulator *sdk.Accumulator resource *resource.Resource - uniq metric.MeterImpl - named map[string]metric.Meter errorHandler sdk.ErrorHandler integrator export.Integrator exporter export.Exporter @@ -42,10 +40,9 @@ type Controller struct { period time.Duration ticker Ticker clock Clock + provider *registry.Provider } -var _ metric.Provider = &Controller{} - // Several types below are created to match "github.com/benbjohnson/clock" // so that it remains a test-only dependency. @@ -83,8 +80,7 @@ func New(integrator export.Integrator, exporter export.Exporter, period time.Dur return &Controller{ accumulator: impl, resource: c.Resource, - uniq: registry.NewUniqueInstrumentMeterImpl(impl), - named: map[string]metric.Meter{}, + provider: registry.NewProvider(impl), errorHandler: c.ErrorHandler, integrator: integrator, exporter: exporter, @@ -102,6 +98,8 @@ func (c *Controller) SetClock(clock Clock) { c.clock = clock } +// SetErrorHandler sets the handler for errors. If none has been set, the +// SDK default error handler is used. func (c *Controller) SetErrorHandler(errorHandler sdk.ErrorHandler) { c.lock.Lock() defer c.lock.Unlock() @@ -109,19 +107,9 @@ func (c *Controller) SetErrorHandler(errorHandler sdk.ErrorHandler) { c.accumulator.SetErrorHandler(errorHandler) } -// Meter returns a named Meter, satisifying the metric.Provider -// interface. -func (c *Controller) Meter(name string) metric.Meter { - c.lock.Lock() - defer c.lock.Unlock() - - if meter, ok := c.named[name]; ok { - return meter - } - - meter := metric.WrapMeterImpl(c.uniq, name) - c.named[name] = meter - return meter +// Provider returns a metric.Provider instance for this controller. +func (c *Controller) Provider() metric.Provider { + return c.provider } // Start begins a ticker that periodically collects and exports diff --git a/sdk/metric/controller/push/push_test.go b/sdk/metric/controller/push/push_test.go index 11dbf4a52..fd200f4d0 100644 --- a/sdk/metric/controller/push/push_test.go +++ b/sdk/metric/controller/push/push_test.go @@ -183,7 +183,7 @@ func TestPushTicker(t *testing.T) { fix := newFixture(t) p := push.New(fix.integrator, fix.exporter, time.Second) - meter := p.Meter("name") + meter := p.Provider().Meter("name") mock := mockClock{clock.NewMock()} p.SetClock(mock) @@ -280,7 +280,7 @@ func TestPushExportError(t *testing.T) { ctx := context.Background() - meter := p.Meter("name") + meter := p.Provider().Meter("name") counter1 := metric.Must(meter).NewInt64Counter("counter1") counter2 := metric.Must(meter).NewInt64Counter("counter2") diff --git a/sdk/metric/example_test.go b/sdk/metric/example_test.go index 4f39441b5..c4910b9bb 100644 --- a/sdk/metric/example_test.go +++ b/sdk/metric/example_test.go @@ -38,7 +38,7 @@ func ExampleNew() { ctx := context.Background() key := kv.Key("key") - meter := pusher.Meter("example") + meter := pusher.Provider().Meter("example") counter := metric.Must(meter).NewInt64Counter("a.counter") From ee3c9ed1a5a662240050fcefc90c3e50b0331c46 Mon Sep 17 00:00:00 2001 From: Joshua MacDonald Date: Mon, 18 May 2020 11:03:43 -0700 Subject: [PATCH 21/21] Rename Observer to ValueObserver (#734) * Observer -> ValueObserver * Move wrappers into async.go --- api/global/internal/meter_test.go | 20 +++++----- api/global/internal/registry_test.go | 8 ++-- api/metric/api_test.go | 20 +++++----- api/metric/async.go | 20 +++++++++- api/metric/kind.go | 4 +- api/metric/kind_string.go | 6 +-- api/metric/meter.go | 40 +++++++++---------- api/metric/must.go | 24 +++++------ api/metric/observer.go | 12 +++--- api/metric/registry/registry_test.go | 8 ++-- api/metric/sync.go | 18 --------- example/basic/main.go | 4 +- example/prometheus/main.go | 4 +- .../metric/prometheus/prometheus_test.go | 2 +- exporters/metric/stdout/stdout_test.go | 8 ++-- exporters/otlp/otlp_integration_test.go | 12 +++--- .../metric/aggregator/aggregator_test.go | 2 +- .../aggregator/lastvalue/lastvalue_test.go | 6 +-- sdk/metric/benchmark_test.go | 12 +++--- sdk/metric/correct_test.go | 30 +++++++------- sdk/metric/integrator/test/test.go | 6 +-- sdk/metric/selector/simple/simple.go | 8 ++-- sdk/metric/selector/simple/simple_test.go | 10 ++--- 23 files changed, 142 insertions(+), 142 deletions(-) diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go index 5c436791d..5d9188c96 100644 --- a/api/global/internal/meter_test.go +++ b/api/global/internal/meter_test.go @@ -86,12 +86,12 @@ func TestDirect(t *testing.T) { valuerecorder.Record(ctx, 1, labels1...) valuerecorder.Record(ctx, 2, labels1...) - _ = Must(meter1).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) { + _ = Must(meter1).RegisterFloat64ValueObserver("test.valueobserver.float", func(result metric.Float64ObserverResult) { result.Observe(1., labels1...) result.Observe(2., labels2...) }) - _ = Must(meter1).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) { + _ = Must(meter1).RegisterInt64ValueObserver("test.valueobserver.int", func(result metric.Int64ObserverResult) { result.Observe(1, labels1...) result.Observe(2, labels2...) }) @@ -132,25 +132,25 @@ func TestDirect(t *testing.T) { Number: asFloat(3), }, { - Name: "test.observer.float", + Name: "test.valueobserver.float", LibraryName: "test1", Labels: asMap(labels1...), Number: asFloat(1), }, { - Name: "test.observer.float", + Name: "test.valueobserver.float", LibraryName: "test1", Labels: asMap(labels2...), Number: asFloat(2), }, { - Name: "test.observer.int", + Name: "test.valueobserver.int", LibraryName: "test1", Labels: asMap(labels1...), Number: asInt(1), }, { - Name: "test.observer.int", + Name: "test.valueobserver.int", LibraryName: "test1", Labels: asMap(labels2...), Number: asInt(2), @@ -331,12 +331,12 @@ func TestImplementationIndirection(t *testing.T) { require.False(t, ok) // Async: no SDK yet - observer := Must(meter1).RegisterFloat64Observer( - "interface.observer", + valueobserver := Must(meter1).RegisterFloat64ValueObserver( + "interface.valueobserver", func(result metric.Float64ObserverResult) {}, ) - ival = observer.AsyncImpl().Implementation() + ival = valueobserver.AsyncImpl().Implementation() require.NotNil(t, ival) _, ok = ival.(*metrictest.Async) @@ -356,7 +356,7 @@ func TestImplementationIndirection(t *testing.T) { require.True(t, ok) // Async - ival = observer.AsyncImpl().Implementation() + ival = valueobserver.AsyncImpl().Implementation() require.NotNil(t, ival) _, ok = ival.(*metrictest.Async) diff --git a/api/global/internal/registry_test.go b/api/global/internal/registry_test.go index 14ae04dfd..76144bf5b 100644 --- a/api/global/internal/registry_test.go +++ b/api/global/internal/registry_test.go @@ -42,11 +42,11 @@ var ( "valuerecorder.float64": func(name, libraryName string) (metric.InstrumentImpl, error) { return unwrap(MeterProvider().Meter(libraryName).NewFloat64ValueRecorder(name)) }, - "observer.int64": func(name, libraryName string) (metric.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).RegisterInt64Observer(name, func(metric.Int64ObserverResult) {})) + "valueobserver.int64": func(name, libraryName string) (metric.InstrumentImpl, error) { + return unwrap(MeterProvider().Meter(libraryName).RegisterInt64ValueObserver(name, func(metric.Int64ObserverResult) {})) }, - "observer.float64": func(name, libraryName string) (metric.InstrumentImpl, error) { - return unwrap(MeterProvider().Meter(libraryName).RegisterFloat64Observer(name, func(metric.Float64ObserverResult) {})) + "valueobserver.float64": func(name, libraryName string) (metric.InstrumentImpl, error) { + return unwrap(MeterProvider().Meter(libraryName).RegisterFloat64ValueObserver(name, func(metric.Float64ObserverResult) {})) }, } ) diff --git a/api/metric/api_test.go b/api/metric/api_test.go index 9a370a8d4..cfcd1a7a4 100644 --- a/api/metric/api_test.go +++ b/api/metric/api_test.go @@ -146,11 +146,11 @@ func TestValueRecorder(t *testing.T) { } } -func TestObserver(t *testing.T) { +func TestObserverInstruments(t *testing.T) { { labels := []kv.KeyValue{kv.String("O", "P")} mockSDK, meter := mockTest.NewMeter() - o := Must(meter).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) { + o := Must(meter).RegisterFloat64ValueObserver("test.observer.float", func(result metric.Float64ObserverResult) { result.Observe(42, labels...) }) t.Log("Testing float observer") @@ -161,7 +161,7 @@ func TestObserver(t *testing.T) { { labels := []kv.KeyValue{} mockSDK, meter := mockTest.NewMeter() - o := Must(meter).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) { + o := Must(meter).RegisterInt64ValueObserver("test.observer.int", func(result metric.Int64ObserverResult) { result.Observe(42, labels...) }) t.Log("Testing int observer") @@ -210,11 +210,11 @@ func checkBatches(t *testing.T, ctx context.Context, labels []kv.KeyValue, mock } } -func TestBatchObserver(t *testing.T) { +func TestBatchObserverInstruments(t *testing.T) { mockSDK, meter := mockTest.NewMeter() - var obs1 metric.Int64Observer - var obs2 metric.Float64Observer + var obs1 metric.Int64ValueObserver + var obs2 metric.Float64ValueObserver labels := []kv.KeyValue{ kv.String("A", "B"), @@ -229,8 +229,8 @@ func TestBatchObserver(t *testing.T) { ) }, ) - obs1 = cb.RegisterInt64Observer("test.observer.int") - obs2 = cb.RegisterFloat64Observer("test.observer.float") + obs1 = cb.RegisterInt64ValueObserver("test.observer.int") + obs2 = cb.RegisterFloat64ValueObserver("test.observer.float") mockSDK.RunAsyncInstruments() @@ -314,7 +314,7 @@ func TestWrappedInstrumentError(t *testing.T) { require.Equal(t, err, metric.ErrSDKReturnedNilImpl) require.NotNil(t, valuerecorder.SyncImpl()) - observer, err := meter.RegisterInt64Observer("test.observer", func(result metric.Int64ObserverResult) {}) + observer, err := meter.RegisterInt64ValueObserver("test.observer", func(result metric.Int64ObserverResult) {}) require.NotNil(t, err) require.NotNil(t, observer.AsyncImpl()) @@ -324,7 +324,7 @@ func TestNilCallbackObserverNoop(t *testing.T) { // Tests that a nil callback yields a no-op observer without error. _, meter := mockTest.NewMeter() - observer := Must(meter).RegisterInt64Observer("test.observer", nil) + observer := Must(meter).RegisterInt64ValueObserver("test.observer", nil) _, ok := observer.AsyncImpl().(metric.NoopAsync) require.True(t, ok) diff --git a/api/metric/async.go b/api/metric/async.go index bd22f714e..7f766e1ed 100644 --- a/api/metric/async.go +++ b/api/metric/async.go @@ -29,7 +29,7 @@ import "go.opentelemetry.io/otel/api/kv" // Observation is used for reporting an asynchronous batch of metric // values. Instances of this type should be created by asynchronous -// instruments (e.g., Int64Observer.Observation()). +// instruments (e.g., Int64ValueObserver.Observation()). type Observation struct { // number needs to be aligned for 64-bit atomic operations. number Number @@ -175,3 +175,21 @@ func (b *BatchObserverCallback) Run(function func([]kv.KeyValue, ...Observation) function: function, }) } + +// wrapInt64ValueObserverInstrument returns an `Int64ValueObserver` from a +// `AsyncImpl`. An error will be generated if the +// `AsyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapInt64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Int64ValueObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Int64ValueObserver{asyncInstrument: common}, err +} + +// wrapFloat64ValueObserverInstrument returns an `Float64ValueObserver` from a +// `AsyncImpl`. An error will be generated if the +// `AsyncImpl` is nil (in which case a No-op is substituted), +// otherwise the error passes through. +func wrapFloat64ValueObserverInstrument(asyncInst AsyncImpl, err error) (Float64ValueObserver, error) { + common, err := checkNewAsync(asyncInst, err) + return Float64ValueObserver{asyncInstrument: common}, err +} diff --git a/api/metric/kind.go b/api/metric/kind.go index 38001e918..cd847a242 100644 --- a/api/metric/kind.go +++ b/api/metric/kind.go @@ -22,8 +22,8 @@ type Kind int8 const ( // ValueRecorderKind indicates a ValueRecorder instrument. ValueRecorderKind Kind = iota - // ObserverKind indicates an Observer instrument. - ObserverKind + // ValueObserverKind indicates an ValueObserver instrument. + ValueObserverKind // CounterKind indicates a Counter instrument. CounterKind ) diff --git a/api/metric/kind_string.go b/api/metric/kind_string.go index 67113b120..a05d5f307 100644 --- a/api/metric/kind_string.go +++ b/api/metric/kind_string.go @@ -9,13 +9,13 @@ func _() { // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[ValueRecorderKind-0] - _ = x[ObserverKind-1] + _ = x[ValueObserverKind-1] _ = x[CounterKind-2] } -const _Kind_name = "ValueRecorderKindObserverKindCounterKind" +const _Kind_name = "ValueRecorderKindValueObserverKindCounterKind" -var _Kind_index = [...]uint8{0, 17, 29, 40} +var _Kind_index = [...]uint8{0, 17, 34, 45} func (i Kind) String() string { if i < 0 || i >= Kind(len(_Kind_index)-1) { diff --git a/api/metric/meter.go b/api/metric/meter.go index 5e95e2812..9cec69ec6 100644 --- a/api/metric/meter.go +++ b/api/metric/meter.go @@ -100,54 +100,54 @@ func (m Meter) NewFloat64ValueRecorder(name string, opts ...Option) (Float64Valu m.newSync(name, ValueRecorderKind, Float64NumberKind, opts)) } -// RegisterInt64Observer creates a new integer Observer instrument +// RegisterInt64ValueObserver creates a new integer ValueObserver instrument // with the given name, running a given callback, and customized with // options. May return an error if the name is invalid (e.g., empty) // or improperly registered (e.g., duplicate registration). -func (m Meter) RegisterInt64Observer(name string, callback Int64ObserverCallback, opts ...Option) (Int64Observer, error) { +func (m Meter) RegisterInt64ValueObserver(name string, callback Int64ObserverCallback, opts ...Option) (Int64ValueObserver, error) { if callback == nil { - return wrapInt64ObserverInstrument(NoopAsync{}, nil) + return wrapInt64ValueObserverInstrument(NoopAsync{}, nil) } - return wrapInt64ObserverInstrument( - m.newAsync(name, ObserverKind, Int64NumberKind, opts, + return wrapInt64ValueObserverInstrument( + m.newAsync(name, ValueObserverKind, Int64NumberKind, opts, newInt64AsyncRunner(callback))) } -// RegisterFloat64Observer creates a new floating point Observer with +// RegisterFloat64ValueObserver creates a new floating point ValueObserver with // the given name, running a given callback, and customized with // options. May return an error if the name is invalid (e.g., empty) // or improperly registered (e.g., duplicate registration). -func (m Meter) RegisterFloat64Observer(name string, callback Float64ObserverCallback, opts ...Option) (Float64Observer, error) { +func (m Meter) RegisterFloat64ValueObserver(name string, callback Float64ObserverCallback, opts ...Option) (Float64ValueObserver, error) { if callback == nil { - return wrapFloat64ObserverInstrument(NoopAsync{}, nil) + return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil) } - return wrapFloat64ObserverInstrument( - m.newAsync(name, ObserverKind, Float64NumberKind, opts, + return wrapFloat64ValueObserverInstrument( + m.newAsync(name, ValueObserverKind, Float64NumberKind, opts, newFloat64AsyncRunner(callback))) } -// RegisterInt64Observer creates a new integer Observer instrument +// RegisterInt64ValueObserver creates a new integer ValueObserver instrument // with the given name, running in a batch callback, and customized with // options. May return an error if the name is invalid (e.g., empty) // or improperly registered (e.g., duplicate registration). -func (b BatchObserver) RegisterInt64Observer(name string, opts ...Option) (Int64Observer, error) { +func (b BatchObserver) RegisterInt64ValueObserver(name string, opts ...Option) (Int64ValueObserver, error) { if b.runner == nil { - return wrapInt64ObserverInstrument(NoopAsync{}, nil) + return wrapInt64ValueObserverInstrument(NoopAsync{}, nil) } - return wrapInt64ObserverInstrument( - b.meter.newAsync(name, ObserverKind, Int64NumberKind, opts, b.runner)) + return wrapInt64ValueObserverInstrument( + b.meter.newAsync(name, ValueObserverKind, Int64NumberKind, opts, b.runner)) } -// RegisterFloat64Observer creates a new floating point Observer with +// RegisterFloat64ValueObserver creates a new floating point ValueObserver with // the given name, running in a batch callback, and customized with // options. May return an error if the name is invalid (e.g., empty) // or improperly registered (e.g., duplicate registration). -func (b BatchObserver) RegisterFloat64Observer(name string, opts ...Option) (Float64Observer, error) { +func (b BatchObserver) RegisterFloat64ValueObserver(name string, opts ...Option) (Float64ValueObserver, error) { if b.runner == nil { - return wrapFloat64ObserverInstrument(NoopAsync{}, nil) + return wrapFloat64ValueObserverInstrument(NoopAsync{}, nil) } - return wrapFloat64ObserverInstrument( - b.meter.newAsync(name, ObserverKind, Float64NumberKind, opts, + return wrapFloat64ValueObserverInstrument( + b.meter.newAsync(name, ValueObserverKind, Float64NumberKind, opts, b.runner)) } diff --git a/api/metric/must.go b/api/metric/must.go index b747932f3..2bfd03310 100644 --- a/api/metric/must.go +++ b/api/metric/must.go @@ -73,20 +73,20 @@ func (mm MeterMust) NewFloat64ValueRecorder(name string, mos ...Option) Float64V } } -// RegisterInt64Observer calls `Meter.RegisterInt64Observer` and +// RegisterInt64ValueObserver calls `Meter.RegisterInt64ValueObserver` and // returns the instrument, panicking if it encounters an error. -func (mm MeterMust) RegisterInt64Observer(name string, callback Int64ObserverCallback, oos ...Option) Int64Observer { - if inst, err := mm.meter.RegisterInt64Observer(name, callback, oos...); err != nil { +func (mm MeterMust) RegisterInt64ValueObserver(name string, callback Int64ObserverCallback, oos ...Option) Int64ValueObserver { + if inst, err := mm.meter.RegisterInt64ValueObserver(name, callback, oos...); err != nil { panic(err) } else { return inst } } -// RegisterFloat64Observer calls `Meter.RegisterFloat64Observer` and +// RegisterFloat64ValueObserver calls `Meter.RegisterFloat64ValueObserver` and // returns the instrument, panicking if it encounters an error. -func (mm MeterMust) RegisterFloat64Observer(name string, callback Float64ObserverCallback, oos ...Option) Float64Observer { - if inst, err := mm.meter.RegisterFloat64Observer(name, callback, oos...); err != nil { +func (mm MeterMust) RegisterFloat64ValueObserver(name string, callback Float64ObserverCallback, oos ...Option) Float64ValueObserver { + if inst, err := mm.meter.RegisterFloat64ValueObserver(name, callback, oos...); err != nil { panic(err) } else { return inst @@ -101,20 +101,20 @@ func (mm MeterMust) NewBatchObserver(callback BatchObserverCallback) BatchObserv } } -// RegisterInt64Observer calls `BatchObserver.RegisterInt64Observer` and +// RegisterInt64ValueObserver calls `BatchObserver.RegisterInt64ValueObserver` and // returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) RegisterInt64Observer(name string, oos ...Option) Int64Observer { - if inst, err := bm.batch.RegisterInt64Observer(name, oos...); err != nil { +func (bm BatchObserverMust) RegisterInt64ValueObserver(name string, oos ...Option) Int64ValueObserver { + if inst, err := bm.batch.RegisterInt64ValueObserver(name, oos...); err != nil { panic(err) } else { return inst } } -// RegisterFloat64Observer calls `BatchObserver.RegisterFloat64Observer` and +// RegisterFloat64ValueObserver calls `BatchObserver.RegisterFloat64ValueObserver` and // returns the instrument, panicking if it encounters an error. -func (bm BatchObserverMust) RegisterFloat64Observer(name string, oos ...Option) Float64Observer { - if inst, err := bm.batch.RegisterFloat64Observer(name, oos...); err != nil { +func (bm BatchObserverMust) RegisterFloat64ValueObserver(name string, oos ...Option) Float64ValueObserver { + if inst, err := bm.batch.RegisterFloat64ValueObserver(name, oos...); err != nil { panic(err) } else { return inst diff --git a/api/metric/observer.go b/api/metric/observer.go index c5b173ff1..9d1a0582c 100644 --- a/api/metric/observer.go +++ b/api/metric/observer.go @@ -21,15 +21,15 @@ type BatchObserver struct { runner AsyncBatchRunner } -// Int64Observer is a metric that captures a set of int64 values at a +// Int64ValueObserver is a metric that captures a set of int64 values at a // point in time. -type Int64Observer struct { +type Int64ValueObserver struct { asyncInstrument } -// Float64Observer is a metric that captures a set of float64 values +// Float64ValueObserver is a metric that captures a set of float64 values // at a point in time. -type Float64Observer struct { +type Float64ValueObserver struct { asyncInstrument } @@ -37,7 +37,7 @@ type Float64Observer struct { // argument, for an asynchronous integer instrument. // This returns an implementation-level object for use by the SDK, // users should not refer to this. -func (i Int64Observer) Observation(v int64) Observation { +func (i Int64ValueObserver) Observation(v int64) Observation { return Observation{ number: NewInt64Number(v), instrument: i.instrument, @@ -48,7 +48,7 @@ func (i Int64Observer) Observation(v int64) Observation { // argument, for an asynchronous integer instrument. // This returns an implementation-level object for use by the SDK, // users should not refer to this. -func (f Float64Observer) Observation(v float64) Observation { +func (f Float64ValueObserver) Observation(v float64) Observation { return Observation{ number: NewFloat64Number(v), instrument: f.instrument, diff --git a/api/metric/registry/registry_test.go b/api/metric/registry/registry_test.go index 3d5991ca8..4f5c10a33 100644 --- a/api/metric/registry/registry_test.go +++ b/api/metric/registry/registry_test.go @@ -43,11 +43,11 @@ var ( "valuerecorder.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { return unwrap(m.NewFloat64ValueRecorder(name)) }, - "observer.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { - return unwrap(m.RegisterInt64Observer(name, func(metric.Int64ObserverResult) {})) + "valueobserver.int64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { + return unwrap(m.RegisterInt64ValueObserver(name, func(metric.Int64ObserverResult) {})) }, - "observer.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { - return unwrap(m.RegisterFloat64Observer(name, func(metric.Float64ObserverResult) {})) + "valueobserver.float64": func(m metric.Meter, name string) (metric.InstrumentImpl, error) { + return unwrap(m.RegisterFloat64ValueObserver(name, func(metric.Float64ObserverResult) {})) }, } ) diff --git a/api/metric/sync.go b/api/metric/sync.go index 66e99c285..2001ff197 100644 --- a/api/metric/sync.go +++ b/api/metric/sync.go @@ -191,21 +191,3 @@ func wrapFloat64ValueRecorderInstrument(syncInst SyncImpl, err error) (Float64Va common, err := checkNewSync(syncInst, err) return Float64ValueRecorder{syncInstrument: common}, err } - -// wrapInt64ObserverInstrument returns an `Int64Observer` from a -// `AsyncImpl`. An error will be generated if the -// `AsyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func wrapInt64ObserverInstrument(asyncInst AsyncImpl, err error) (Int64Observer, error) { - common, err := checkNewAsync(asyncInst, err) - return Int64Observer{asyncInstrument: common}, err -} - -// wrapFloat64ObserverInstrument returns an `Float64Observer` from a -// `AsyncImpl`. An error will be generated if the -// `AsyncImpl` is nil (in which case a No-op is substituted), -// otherwise the error passes through. -func wrapFloat64ObserverInstrument(asyncInst AsyncImpl, err error) (Float64Observer, error) { - common, err := checkNewAsync(asyncInst, err) - return Float64Observer{asyncInstrument: common}, err -} diff --git a/example/basic/main.go b/example/basic/main.go index 84470d10b..04c4f8e49 100644 --- a/example/basic/main.go +++ b/example/basic/main.go @@ -76,8 +76,8 @@ func main() { oneMetricCB := func(result metric.Float64ObserverResult) { result.Observe(1, commonLabels...) } - _ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", oneMetricCB, - metric.WithDescription("An observer set to 1.0"), + _ = metric.Must(meter).RegisterFloat64ValueObserver("ex.com.one", oneMetricCB, + metric.WithDescription("A ValueObserver set to 1.0"), ) valuerecorderTwo := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two") diff --git a/example/prometheus/main.go b/example/prometheus/main.go index f9a5cf702..4fbf94baa 100644 --- a/example/prometheus/main.go +++ b/example/prometheus/main.go @@ -59,8 +59,8 @@ func main() { (*observerLock).RUnlock() result.Observe(value, labels...) } - _ = metric.Must(meter).RegisterFloat64Observer("ex.com.one", cb, - metric.WithDescription("An observer set to 1.0"), + _ = metric.Must(meter).RegisterFloat64ValueObserver("ex.com.one", cb, + metric.WithDescription("A ValueObserver set to 1.0"), ) valuerecorder := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two") diff --git a/exporters/metric/prometheus/prometheus_test.go b/exporters/metric/prometheus/prometheus_test.go index 0505281a4..f30813b06 100644 --- a/exporters/metric/prometheus/prometheus_test.go +++ b/exporters/metric/prometheus/prometheus_test.go @@ -44,7 +44,7 @@ func TestPrometheusExporter(t *testing.T) { counter := metric.NewDescriptor( "counter", metric.CounterKind, metric.Float64NumberKind) lastValue := metric.NewDescriptor( - "lastvalue", metric.ObserverKind, metric.Float64NumberKind) + "lastvalue", metric.ValueObserverKind, metric.Float64NumberKind) valuerecorder := metric.NewDescriptor( "valuerecorder", metric.ValueRecorderKind, metric.Float64NumberKind) histogramValueRecorder := metric.NewDescriptor( diff --git a/exporters/metric/stdout/stdout_test.go b/exporters/metric/stdout/stdout_test.go index 918c47b8b..2dee68e55 100644 --- a/exporters/metric/stdout/stdout_test.go +++ b/exporters/metric/stdout/stdout_test.go @@ -98,7 +98,7 @@ func TestStdoutTimestamp(t *testing.T) { checkpointSet := test.NewCheckpointSet() ctx := context.Background() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Int64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Int64NumberKind) lvagg := lastvalue.New() aggtest.CheckedUpdate(t, lvagg, metric.NewInt64Number(321), &desc) lvagg.Checkpoint(ctx, &desc) @@ -160,7 +160,7 @@ func TestStdoutLastValueFormat(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Float64NumberKind) lvagg := lastvalue.New() aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc) lvagg.Checkpoint(fix.ctx, &desc) @@ -268,7 +268,7 @@ func TestStdoutLastValueNotSet(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Float64NumberKind) lvagg := lastvalue.New() lvagg.Checkpoint(fix.ctx, &desc) @@ -318,7 +318,7 @@ func TestStdoutResource(t *testing.T) { checkpointSet := test.NewCheckpointSet() - desc := metric.NewDescriptor("test.name", metric.ObserverKind, metric.Float64NumberKind) + desc := metric.NewDescriptor("test.name", metric.ValueObserverKind, metric.Float64NumberKind) lvagg := lastvalue.New() aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc) lvagg.Checkpoint(fix.ctx, &desc) diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go index 54aae4f0c..a7a764a49 100644 --- a/exporters/otlp/otlp_integration_test.go +++ b/exporters/otlp/otlp_integration_test.go @@ -128,8 +128,8 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) "test-float64-counter": {metric.CounterKind, metricapi.Float64NumberKind, 1}, "test-int64-valuerecorder": {metric.ValueRecorderKind, metricapi.Int64NumberKind, 2}, "test-float64-valuerecorder": {metric.ValueRecorderKind, metricapi.Float64NumberKind, 2}, - "test-int64-observer": {metric.ObserverKind, metricapi.Int64NumberKind, 3}, - "test-float64-observer": {metric.ObserverKind, metricapi.Float64NumberKind, 3}, + "test-int64-valueobserver": {metric.ValueObserverKind, metricapi.Int64NumberKind, 3}, + "test-float64-valueobserver": {metric.ValueObserverKind, metricapi.Float64NumberKind, 3}, } for name, data := range instruments { switch data.iKind { @@ -151,18 +151,18 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) default: assert.Failf(t, "unsupported number testing kind", data.nKind.String()) } - case metric.ObserverKind: + case metric.ValueObserverKind: switch data.nKind { case metricapi.Int64NumberKind: callback := func(v int64) metricapi.Int64ObserverCallback { return metricapi.Int64ObserverCallback(func(result metricapi.Int64ObserverResult) { result.Observe(v, labels...) }) }(data.val) - metricapi.Must(meter).RegisterInt64Observer(name, callback) + metricapi.Must(meter).RegisterInt64ValueObserver(name, callback) case metricapi.Float64NumberKind: callback := func(v float64) metricapi.Float64ObserverCallback { return metricapi.Float64ObserverCallback(func(result metricapi.Float64ObserverResult) { result.Observe(v, labels...) }) }(float64(data.val)) - metricapi.Must(meter).RegisterFloat64Observer(name, callback) + metricapi.Must(meter).RegisterFloat64ValueObserver(name, callback) default: assert.Failf(t, "unsupported number testing kind", data.nKind.String()) } @@ -246,7 +246,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption) default: assert.Failf(t, "invalid number kind", data.nKind.String()) } - case metric.ValueRecorderKind, metric.ObserverKind: + case metric.ValueRecorderKind, metric.ValueObserverKind: assert.Equal(t, metricpb.MetricDescriptor_SUMMARY.String(), desc.GetType().String()) m.GetSummaryDataPoints() if dp := m.GetSummaryDataPoints(); assert.Len(t, dp, 1) { diff --git a/sdk/export/metric/aggregator/aggregator_test.go b/sdk/export/metric/aggregator/aggregator_test.go index 0083a71a2..ce7624949 100644 --- a/sdk/export/metric/aggregator/aggregator_test.go +++ b/sdk/export/metric/aggregator/aggregator_test.go @@ -87,7 +87,7 @@ func TestNaNTest(t *testing.T) { for _, mkind := range []metric.Kind{ metric.CounterKind, metric.ValueRecorderKind, - metric.ObserverKind, + metric.ValueObserverKind, } { desc := metric.NewDescriptor( "name", diff --git a/sdk/metric/aggregator/lastvalue/lastvalue_test.go b/sdk/metric/aggregator/lastvalue/lastvalue_test.go index 49b9e6970..1b4da094f 100644 --- a/sdk/metric/aggregator/lastvalue/lastvalue_test.go +++ b/sdk/metric/aggregator/lastvalue/lastvalue_test.go @@ -55,7 +55,7 @@ func TestLastValueUpdate(t *testing.T) { test.RunProfiles(t, func(t *testing.T, profile test.Profile) { agg := New() - record := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind) + record := test.NewAggregatorTest(metric.ValueObserverKind, profile.NumberKind) var last metric.Number for i := 0; i < count; i++ { @@ -79,7 +79,7 @@ func TestLastValueMerge(t *testing.T) { agg1 := New() agg2 := New() - descriptor := test.NewAggregatorTest(metric.ObserverKind, profile.NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueObserverKind, profile.NumberKind) first1 := profile.Random(+1) first2 := profile.Random(+1) @@ -107,7 +107,7 @@ func TestLastValueMerge(t *testing.T) { } func TestLastValueNotSet(t *testing.T) { - descriptor := test.NewAggregatorTest(metric.ObserverKind, metric.Int64NumberKind) + descriptor := test.NewAggregatorTest(metric.ValueObserverKind, metric.Int64NumberKind) g := New() g.Checkpoint(context.Background(), descriptor) diff --git a/sdk/metric/benchmark_test.go b/sdk/metric/benchmark_test.go index 06c8a980b..3a6b9888d 100644 --- a/sdk/metric/benchmark_test.go +++ b/sdk/metric/benchmark_test.go @@ -423,22 +423,22 @@ func BenchmarkObserverRegistration(b *testing.B) { fix := newFixture(b) names := make([]string, 0, b.N) for i := 0; i < b.N; i++ { - names = append(names, fmt.Sprintf("test.observer.%d", i)) + names = append(names, fmt.Sprintf("test.valueobserver.%d", i)) } cb := func(result metric.Int64ObserverResult) {} b.ResetTimer() for i := 0; i < b.N; i++ { - fix.meter.RegisterInt64Observer(names[i], cb) + fix.meter.RegisterInt64ValueObserver(names[i], cb) } } -func BenchmarkObserverObservationInt64(b *testing.B) { +func BenchmarkValueObserverObservationInt64(b *testing.B) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - _ = fix.meter.RegisterInt64Observer("test.observer", func(result metric.Int64ObserverResult) { + _ = fix.meter.RegisterInt64ValueObserver("test.valueobserver", func(result metric.Int64ObserverResult) { for i := 0; i < b.N; i++ { result.Observe((int64)(i), labs...) } @@ -449,11 +449,11 @@ func BenchmarkObserverObservationInt64(b *testing.B) { fix.accumulator.Collect(ctx) } -func BenchmarkObserverObservationFloat64(b *testing.B) { +func BenchmarkValueObserverObservationFloat64(b *testing.B) { ctx := context.Background() fix := newFixture(b) labs := makeLabels(1) - _ = fix.meter.RegisterFloat64Observer("test.observer", func(result metric.Float64ObserverResult) { + _ = fix.meter.RegisterFloat64ValueObserver("test.valueobserver", func(result metric.Float64ObserverResult) { for i := 0; i < b.N; i++ { result.Observe((float64)(i), labs...) } diff --git a/sdk/metric/correct_test.go b/sdk/metric/correct_test.go index e26aa630a..686e168a5 100644 --- a/sdk/metric/correct_test.go +++ b/sdk/metric/correct_test.go @@ -291,20 +291,20 @@ func TestObserverCollection(t *testing.T) { sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") - _ = Must(meter).RegisterFloat64Observer("float.observer", func(result metric.Float64ObserverResult) { + _ = Must(meter).RegisterFloat64ValueObserver("float.valueobserver", func(result metric.Float64ObserverResult) { result.Observe(1, kv.String("A", "B")) // last value wins result.Observe(-1, kv.String("A", "B")) result.Observe(-1, kv.String("C", "D")) }) - _ = Must(meter).RegisterInt64Observer("int.observer", func(result metric.Int64ObserverResult) { + _ = Must(meter).RegisterInt64ValueObserver("int.valueobserver", func(result metric.Int64ObserverResult) { result.Observe(-1, kv.String("A", "B")) result.Observe(1) // last value wins result.Observe(1, kv.String("A", "B")) result.Observe(1) }) - _ = Must(meter).RegisterInt64Observer("empty.observer", func(result metric.Int64ObserverResult) { + _ = Must(meter).RegisterInt64ValueObserver("empty.valueobserver", func(result metric.Int64ObserverResult) { }) collected := sdk.Collect(ctx) @@ -317,10 +317,10 @@ func TestObserverCollection(t *testing.T) { _ = out.AddTo(rec) } require.EqualValues(t, map[string]float64{ - "float.observer/A=B": -1, - "float.observer/C=D": -1, - "int.observer/": 1, - "int.observer/A=B": 1, + "float.valueobserver/A=B": -1, + "float.valueobserver/C=D": -1, + "int.valueobserver/": 1, + "int.valueobserver/A=B": 1, }, out.Map) } @@ -333,8 +333,8 @@ func TestObserverBatch(t *testing.T) { sdk := metricsdk.NewAccumulator(integrator) meter := metric.WrapMeterImpl(sdk, "test") - var floatObs metric.Float64Observer - var intObs metric.Int64Observer + var floatObs metric.Float64ValueObserver + var intObs metric.Int64ValueObserver var batch = Must(meter).NewBatchObserver( func(result metric.BatchObserverResult) { result.Observe( @@ -358,8 +358,8 @@ func TestObserverBatch(t *testing.T) { intObs.Observation(1), ) }) - floatObs = batch.RegisterFloat64Observer("float.observer") - intObs = batch.RegisterInt64Observer("int.observer") + floatObs = batch.RegisterFloat64ValueObserver("float.valueobserver") + intObs = batch.RegisterInt64ValueObserver("int.valueobserver") collected := sdk.Collect(ctx) @@ -371,10 +371,10 @@ func TestObserverBatch(t *testing.T) { _ = out.AddTo(rec) } require.EqualValues(t, map[string]float64{ - "float.observer/A=B": -1, - "float.observer/C=D": -1, - "int.observer/": 1, - "int.observer/A=B": 1, + "float.valueobserver/A=B": -1, + "float.valueobserver/C=D": -1, + "int.valueobserver/": 1, + "int.valueobserver/A=B": 1, }, out.Map) } diff --git a/sdk/metric/integrator/test/test.go b/sdk/metric/integrator/test/test.go index 383c77645..5f18425a8 100644 --- a/sdk/metric/integrator/test/test.go +++ b/sdk/metric/integrator/test/test.go @@ -47,9 +47,9 @@ type ( var ( // LastValueADesc and LastValueBDesc group by "G" LastValueADesc = metric.NewDescriptor( - "lastvalue.a", metric.ObserverKind, metric.Int64NumberKind) + "lastvalue.a", metric.ValueObserverKind, metric.Int64NumberKind) LastValueBDesc = metric.NewDescriptor( - "lastvalue.b", metric.ObserverKind, metric.Int64NumberKind) + "lastvalue.b", metric.ValueObserverKind, metric.Int64NumberKind) // CounterADesc and CounterBDesc group by "C" CounterADesc = metric.NewDescriptor( "sum.a", metric.CounterKind, metric.Int64NumberKind) @@ -92,7 +92,7 @@ func (*testAggregationSelector) AggregatorFor(desc *metric.Descriptor) export.Ag switch desc.MetricKind() { case metric.CounterKind: return sum.New() - case metric.ObserverKind: + case metric.ValueObserverKind: return lastvalue.New() default: panic("Invalid descriptor MetricKind for this test") diff --git a/sdk/metric/selector/simple/simple.go b/sdk/metric/selector/simple/simple.go index 3f7517585..b27d0af47 100644 --- a/sdk/metric/selector/simple/simple.go +++ b/sdk/metric/selector/simple/simple.go @@ -81,7 +81,7 @@ func NewWithHistogramDistribution(boundaries []metric.Number) export.Aggregation func (selectorInexpensive) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { switch descriptor.MetricKind() { - case metric.ObserverKind: + case metric.ValueObserverKind: fallthrough case metric.ValueRecorderKind: return minmaxsumcount.New(descriptor) @@ -92,7 +92,7 @@ func (selectorInexpensive) AggregatorFor(descriptor *metric.Descriptor) export.A func (s selectorSketch) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { switch descriptor.MetricKind() { - case metric.ObserverKind: + case metric.ValueObserverKind: fallthrough case metric.ValueRecorderKind: return ddsketch.New(s.config, descriptor) @@ -103,7 +103,7 @@ func (s selectorSketch) AggregatorFor(descriptor *metric.Descriptor) export.Aggr func (selectorExact) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { switch descriptor.MetricKind() { - case metric.ObserverKind: + case metric.ValueObserverKind: fallthrough case metric.ValueRecorderKind: return array.New() @@ -114,7 +114,7 @@ func (selectorExact) AggregatorFor(descriptor *metric.Descriptor) export.Aggrega func (s selectorHistogram) AggregatorFor(descriptor *metric.Descriptor) export.Aggregator { switch descriptor.MetricKind() { - case metric.ObserverKind: + case metric.ValueObserverKind: fallthrough case metric.ValueRecorderKind: return histogram.New(descriptor, s.boundaries) diff --git a/sdk/metric/selector/simple/simple_test.go b/sdk/metric/selector/simple/simple_test.go index a80c62ac2..018d49efa 100644 --- a/sdk/metric/selector/simple/simple_test.go +++ b/sdk/metric/selector/simple/simple_test.go @@ -31,33 +31,33 @@ import ( var ( testCounterDesc = metric.NewDescriptor("counter", metric.CounterKind, metric.Int64NumberKind) testValueRecorderDesc = metric.NewDescriptor("valuerecorder", metric.ValueRecorderKind, metric.Int64NumberKind) - testObserverDesc = metric.NewDescriptor("observer", metric.ObserverKind, metric.Int64NumberKind) + testValueObserverDesc = metric.NewDescriptor("valueobserver", metric.ValueObserverKind, metric.Int64NumberKind) ) func TestInexpensiveDistribution(t *testing.T) { inex := simple.NewWithInexpensiveDistribution() require.NotPanics(t, func() { _ = inex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) require.NotPanics(t, func() { _ = inex.AggregatorFor(&testValueRecorderDesc).(*minmaxsumcount.Aggregator) }) - require.NotPanics(t, func() { _ = inex.AggregatorFor(&testObserverDesc).(*minmaxsumcount.Aggregator) }) + require.NotPanics(t, func() { _ = inex.AggregatorFor(&testValueObserverDesc).(*minmaxsumcount.Aggregator) }) } func TestSketchDistribution(t *testing.T) { sk := simple.NewWithSketchDistribution(ddsketch.NewDefaultConfig()) require.NotPanics(t, func() { _ = sk.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) require.NotPanics(t, func() { _ = sk.AggregatorFor(&testValueRecorderDesc).(*ddsketch.Aggregator) }) - require.NotPanics(t, func() { _ = sk.AggregatorFor(&testObserverDesc).(*ddsketch.Aggregator) }) + require.NotPanics(t, func() { _ = sk.AggregatorFor(&testValueObserverDesc).(*ddsketch.Aggregator) }) } func TestExactDistribution(t *testing.T) { ex := simple.NewWithExactDistribution() require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueRecorderDesc).(*array.Aggregator) }) - require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*array.Aggregator) }) + require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueObserverDesc).(*array.Aggregator) }) } func TestHistogramDistribution(t *testing.T) { ex := simple.NewWithHistogramDistribution([]metric.Number{}) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testCounterDesc).(*sum.Aggregator) }) require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueRecorderDesc).(*histogram.Aggregator) }) - require.NotPanics(t, func() { _ = ex.AggregatorFor(&testObserverDesc).(*histogram.Aggregator) }) + require.NotPanics(t, func() { _ = ex.AggregatorFor(&testValueObserverDesc).(*histogram.Aggregator) }) }