diff --git a/.github/ISSUE_TEMPLATE/version_release.md b/.github/ISSUE_TEMPLATE/version_release.md new file mode 100644 index 00000000000..f0a7c0a975a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/version_release.md @@ -0,0 +1,22 @@ +--- +name: Version Release +about: Checklist to follow when shipping a new release. +title: 'Release Checklist' +labels: '' +assignees: '' + +--- + + + +- [ ] Complete [Milestone](https://github.com/open-telemetry/opentelemetry-go/milestone/) + +- [ ] Update contrib codebase to support changes about to be released (use a git sha version) +- [ ] [Pre-release](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#pre-release) +- [ ] [Tag](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#tag) +- [ ] [Release](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#release) +- [ ] [Check examples](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#verify-examples) +- [ ] [Sync with Contrib](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md#upgrade-goopentelemetryiootel-packages) +- [ ] [Release contrib](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/main/RELEASING.md#release-process) +- [ ] [Sync website docs](https://github.com/open-telemetry/opentelemetry-go/blob/main/RELEASING.md#website-documentation) +- [ ] Close the milestone diff --git a/.gitignore b/.gitignore index 99230bae28b..0b605b3d67d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ coverage.* gen/ /example/fib/fib +/example/fib/traces.txt /example/jaeger/jaeger /example/namedtracer/namedtracer /example/opencensus/opencensus diff --git a/.lycheeignore b/.lycheeignore index d300b3f801f..545d634525d 100644 --- a/.lycheeignore +++ b/.lycheeignore @@ -1,2 +1,3 @@ http://localhost http://jaeger-collector +https://github.com/open-telemetry/opentelemetry-go/milestone/ diff --git a/CHANGELOG.md b/CHANGELOG.md index ca0334fbcea..d94994675e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,14 +8,27 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added + +- Add support for `opentracing.TextMap` format in the `Inject` and `Extract` methods +of the `"go.opentelemetry.io/otel/bridge/opentracing".BridgeTracer` type. (#2911) + ### Changed - The `crosslink` make target has been updated to use the `go.opentelemetry.io/build-tools/crosslink` package. (#2886) +- In the `go.opentelemetry.io/otel/sdk/instrumentation` package rename `Library` to `Scope` and alias `Library` as `Scope` (#2976) ### Removed - Support for go1.16. Support is now only for go1.17 and go1.18 (#2917) +### Deprecated + +- The `Library` struct in the `go.opentelemetry.io/otel/sdk/instrumentation` package is deprecated. + Use the equivalent `Scope` struct instead. (#2977) +- The `ReadOnlySpan.InstrumentationLibrary` method from the `go.opentelemetry.io/otel/sdk/trace` package is deprecated. + Use the equivalent `ReadOnlySpan.InstrumentationScope` method instead. (#2977) + ## [1.7.0/0.30.0] - 2022-04-28 ### Added diff --git a/baggage/baggage.go b/baggage/baggage.go index 9f82a2507b8..eba180e04f8 100644 --- a/baggage/baggage.go +++ b/baggage/baggage.go @@ -157,7 +157,7 @@ func (p Property) Key() string { return p.key } -// Value returns the Property value. Additionally a boolean value is returned +// Value returns the Property value. Additionally, a boolean value is returned // indicating if the returned value is the empty if the Property has a value // that is empty or if the value is not set. func (p Property) Value() (string, bool) { @@ -392,7 +392,7 @@ func New(members ...Member) (Baggage, error) { } } - // Check member numbers after deduplicating. + // Check member numbers after deduplication. if len(b) > maxMembers { return Baggage{}, errMemberNumber } @@ -454,7 +454,7 @@ func Parse(bStr string) (Baggage, error) { func (b Baggage) Member(key string) Member { v, ok := b.list[key] if !ok { - // We do not need to worry about distiguising between the situation + // We do not need to worry about distinguishing between the situation // where a zero-valued Member is included in the Baggage because a // zero-valued Member is invalid according to the W3C Baggage // specification (it has an empty key). diff --git a/bridge/opentracing/bridge.go b/bridge/opentracing/bridge.go index 947321debc0..2927e86535a 100644 --- a/bridge/opentracing/bridge.go +++ b/bridge/opentracing/bridge.go @@ -634,7 +634,7 @@ func (s fakeSpan) SpanContext() trace.SpanContext { // Inject is a part of the implementation of the OpenTracing Tracer // interface. // -// Currently only the HTTPHeaders format is supported. +// Currently only the HTTPHeaders and TextMap formats are supported. func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier interface{}) error { bridgeSC, ok := sm.(*bridgeSpanContext) if !ok { @@ -643,38 +643,75 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int if !bridgeSC.otelSpanContext.IsValid() { return ot.ErrInvalidSpanContext } - if builtinFormat, ok := format.(ot.BuiltinFormat); !ok || builtinFormat != ot.HTTPHeaders { + + builtinFormat, ok := format.(ot.BuiltinFormat) + if !ok { return ot.ErrUnsupportedFormat } - hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier) - if !ok { - return ot.ErrInvalidCarrier + + var textCarrier propagation.TextMapCarrier + + switch builtinFormat { + case ot.HTTPHeaders: + hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier) + if !ok { + return ot.ErrInvalidCarrier + } + + textCarrier = propagation.HeaderCarrier(hhcarrier) + case ot.TextMap: + if textCarrier, ok = carrier.(propagation.TextMapCarrier); !ok { + var err error + if textCarrier, err = newTextMapWrapperForInject(carrier); err != nil { + return err + } + } + default: + return ot.ErrUnsupportedFormat } - header := http.Header(hhcarrier) + fs := fakeSpan{ Span: noopSpan, sc: bridgeSC.otelSpanContext, } ctx := trace.ContextWithSpan(context.Background(), fs) ctx = baggage.ContextWithBaggage(ctx, bridgeSC.bag) - t.getPropagator().Inject(ctx, propagation.HeaderCarrier(header)) + t.getPropagator().Inject(ctx, textCarrier) return nil } // Extract is a part of the implementation of the OpenTracing Tracer // interface. // -// Currently only the HTTPHeaders format is supported. +// Currently only the HTTPHeaders and TextMap formats are supported. func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.SpanContext, error) { - if builtinFormat, ok := format.(ot.BuiltinFormat); !ok || builtinFormat != ot.HTTPHeaders { + builtinFormat, ok := format.(ot.BuiltinFormat) + if !ok { return nil, ot.ErrUnsupportedFormat } - hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier) - if !ok { - return nil, ot.ErrInvalidCarrier + + var textCarrier propagation.TextMapCarrier + + switch builtinFormat { + case ot.HTTPHeaders: + hhcarrier, ok := carrier.(ot.HTTPHeadersCarrier) + if !ok { + return nil, ot.ErrInvalidCarrier + } + + textCarrier = propagation.HeaderCarrier(hhcarrier) + case ot.TextMap: + if textCarrier, ok = carrier.(propagation.TextMapCarrier); !ok { + var err error + if textCarrier, err = newTextMapWrapperForExtract(carrier); err != nil { + return nil, err + } + } + default: + return nil, ot.ErrUnsupportedFormat } - header := http.Header(hhcarrier) - ctx := t.getPropagator().Extract(context.Background(), propagation.HeaderCarrier(header)) + + ctx := t.getPropagator().Extract(context.Background(), textCarrier) bag := baggage.FromContext(ctx) bridgeSC := &bridgeSpanContext{ bag: bag, @@ -692,3 +729,105 @@ func (t *BridgeTracer) getPropagator() propagation.TextMapPropagator { } return otel.GetTextMapPropagator() } + +// textMapWrapper Provides operating.TextMapWriter and operating.TextMapReader to +// propagation.TextMapCarrier compatibility. +// Usually, Inject method will only use the write-related interface. +// Extract method will only use the reade-related interface. +// To avoid panic, +// when the carrier implements only one of the interfaces, +// it provides a default implementation of the other interface (textMapWriter and textMapReader). +type textMapWrapper struct { + ot.TextMapWriter + ot.TextMapReader + readerMap map[string]string +} + +func (t *textMapWrapper) Get(key string) string { + if t.readerMap == nil { + t.loadMap() + } + + return t.readerMap[key] +} + +func (t *textMapWrapper) Set(key string, value string) { + t.TextMapWriter.Set(key, value) +} + +func (t *textMapWrapper) Keys() []string { + if t.readerMap == nil { + t.loadMap() + } + + str := make([]string, 0, len(t.readerMap)) + for key := range t.readerMap { + str = append(str, key) + } + + return str +} + +func (t *textMapWrapper) loadMap() { + t.readerMap = make(map[string]string) + + _ = t.ForeachKey(func(key, val string) error { + t.readerMap[key] = val + + return nil + }) +} + +func newTextMapWrapperForExtract(carrier interface{}) (*textMapWrapper, error) { + t := &textMapWrapper{} + + reader, ok := carrier.(ot.TextMapReader) + if !ok { + return nil, ot.ErrInvalidCarrier + } + + t.TextMapReader = reader + + writer, ok := carrier.(ot.TextMapWriter) + if ok { + t.TextMapWriter = writer + } else { + t.TextMapWriter = &textMapWriter{} + } + + return t, nil +} + +func newTextMapWrapperForInject(carrier interface{}) (*textMapWrapper, error) { + t := &textMapWrapper{} + + writer, ok := carrier.(ot.TextMapWriter) + if !ok { + return nil, ot.ErrInvalidCarrier + } + + t.TextMapWriter = writer + + reader, ok := carrier.(ot.TextMapReader) + if ok { + t.TextMapReader = reader + } else { + t.TextMapReader = &textMapReader{} + } + + return t, nil +} + +type textMapWriter struct { +} + +func (t *textMapWriter) Set(key string, value string) { + // maybe print a warning log. +} + +type textMapReader struct { +} + +func (t *textMapReader) ForeachKey(handler func(key, val string) error) error { + return nil // maybe print a warning log. +} diff --git a/bridge/opentracing/bridge_test.go b/bridge/opentracing/bridge_test.go new file mode 100644 index 00000000000..eea3091f265 --- /dev/null +++ b/bridge/opentracing/bridge_test.go @@ -0,0 +1,362 @@ +// 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 opentracing + +import ( + "context" + "errors" + "net/http" + "strings" + "testing" + + ot "github.com/opentracing/opentracing-go" + "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/trace" +) + +type testOnlyTextMapReader struct { +} + +func newTestOnlyTextMapReader() *testOnlyTextMapReader { + return &testOnlyTextMapReader{} +} + +func (t *testOnlyTextMapReader) ForeachKey(handler func(key string, val string) error) error { + _ = handler("key1", "val1") + _ = handler("key2", "val2") + + return nil +} + +type testOnlyTextMapWriter struct { + m map[string]string +} + +func newTestOnlyTextMapWriter() *testOnlyTextMapWriter { + return &testOnlyTextMapWriter{m: map[string]string{}} +} + +func (t *testOnlyTextMapWriter) Set(key, val string) { + t.m[key] = val +} + +type testTextMapReaderAndWriter struct { + *testOnlyTextMapReader + *testOnlyTextMapWriter +} + +func newTestTextMapReaderAndWriter() *testTextMapReaderAndWriter { + return &testTextMapReaderAndWriter{ + testOnlyTextMapReader: newTestOnlyTextMapReader(), + testOnlyTextMapWriter: newTestOnlyTextMapWriter(), + } +} + +func TestTextMapWrapper_New(t *testing.T) { + _, err := newTextMapWrapperForExtract(newTestOnlyTextMapReader()) + assert.NoError(t, err) + + _, err = newTextMapWrapperForExtract(newTestOnlyTextMapWriter()) + assert.True(t, errors.Is(err, ot.ErrInvalidCarrier)) + + _, err = newTextMapWrapperForExtract(newTestTextMapReaderAndWriter()) + assert.NoError(t, err) + + _, err = newTextMapWrapperForInject(newTestOnlyTextMapWriter()) + assert.NoError(t, err) + + _, err = newTextMapWrapperForInject(newTestOnlyTextMapReader()) + assert.True(t, errors.Is(err, ot.ErrInvalidCarrier)) + + _, err = newTextMapWrapperForInject(newTestTextMapReaderAndWriter()) + assert.NoError(t, err) +} + +func TestTextMapWrapper_action(t *testing.T) { + testExtractFunc := func(carrier propagation.TextMapCarrier) { + str := carrier.Keys() + assert.Len(t, str, 2) + assert.Contains(t, str, "key1", "key2") + + assert.Equal(t, carrier.Get("key1"), "val1") + assert.Equal(t, carrier.Get("key2"), "val2") + } + + testInjectFunc := func(carrier propagation.TextMapCarrier) { + carrier.Set("key1", "val1") + carrier.Set("key2", "val2") + + wrap, ok := carrier.(*textMapWrapper) + assert.True(t, ok) + + writer, ok := wrap.TextMapWriter.(*testOnlyTextMapWriter) + if ok { + assert.Contains(t, writer.m, "key1", "key2", "val1", "val2") + return + } + + writer2, ok := wrap.TextMapWriter.(*testTextMapReaderAndWriter) + assert.True(t, ok) + assert.Contains(t, writer2.m, "key1", "key2", "val1", "val2") + } + + onlyWriter, err := newTextMapWrapperForExtract(newTestOnlyTextMapReader()) + assert.NoError(t, err) + testExtractFunc(onlyWriter) + + onlyReader, err := newTextMapWrapperForInject(&testOnlyTextMapWriter{m: map[string]string{}}) + assert.NoError(t, err) + testInjectFunc(onlyReader) + + both, err := newTextMapWrapperForExtract(newTestTextMapReaderAndWriter()) + assert.NoError(t, err) + testExtractFunc(both) + + both, err = newTextMapWrapperForInject(newTestTextMapReaderAndWriter()) + assert.NoError(t, err) + testInjectFunc(both) +} + +var ( + testHeader = "test-trace-id" + traceID trace.TraceID = [16]byte{byte(10)} + spanID trace.SpanID = [8]byte{byte(11)} +) + +type testTextMapPropagator struct { +} + +func (t testTextMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { + carrier.Set(testHeader, strings.Join([]string{traceID.String(), spanID.String()}, ":")) + + // Test for panic + _ = carrier.Get("test") + _ = carrier.Keys() +} + +func (t testTextMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { + traces := carrier.Get(testHeader) + + str := strings.Split(traces, ":") + if len(str) != 2 { + return ctx + } + + var exist = false + + for _, key := range carrier.Keys() { + if strings.EqualFold(testHeader, key) { + exist = true + + break + } + } + + if !exist { + return ctx + } + + var ( + traceID, _ = trace.TraceIDFromHex(str[0]) + spanID, _ = trace.SpanIDFromHex(str[1]) + sc = trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: traceID, + SpanID: spanID, + }) + ) + + // Test for panic + carrier.Set("key", "val") + + return trace.ContextWithRemoteSpanContext(ctx, sc) +} + +func (t testTextMapPropagator) Fields() []string { + return []string{"test"} +} + +// textMapCarrier Implemented propagation.TextMapCarrier interface. +type textMapCarrier struct { + m map[string]string +} + +func newTextCarrier() *textMapCarrier { + return &textMapCarrier{m: map[string]string{}} +} + +func (t *textMapCarrier) Get(key string) string { + return t.m[key] +} + +func (t *textMapCarrier) Set(key string, value string) { + t.m[key] = value +} + +func (t *textMapCarrier) Keys() []string { + str := make([]string, 0, len(t.m)) + + for key := range t.m { + str = append(str, key) + } + + return str +} + +// testTextMapReader only implemented opentracing.TextMapReader interface. +type testTextMapReader struct { + m *map[string]string +} + +func newTestTextMapReader(m *map[string]string) *testTextMapReader { + return &testTextMapReader{m: m} +} + +func (t *testTextMapReader) ForeachKey(handler func(key string, val string) error) error { + for key, val := range *t.m { + if err := handler(key, val); err != nil { + return err + } + } + + return nil +} + +// testTextMapWriter only implemented opentracing.TextMapWriter interface. +type testTextMapWriter struct { + m *map[string]string +} + +func newTestTextMapWriter(m *map[string]string) *testTextMapWriter { + return &testTextMapWriter{m: m} +} + +func (t *testTextMapWriter) Set(key, val string) { + (*t.m)[key] = val +} + +func TestBridgeTracer_ExtractAndInject(t *testing.T) { + bridge := NewBridgeTracer() + bridge.SetTextMapPropagator(new(testTextMapPropagator)) + + tmc := newTextCarrier() + shareMap := map[string]string{} + otTextMap := ot.TextMapCarrier{} + httpHeader := ot.HTTPHeadersCarrier(http.Header{}) + + testCases := []struct { + name string + injectCarrierType ot.BuiltinFormat + extractCarrierType ot.BuiltinFormat + extractCarrier interface{} + injectCarrier interface{} + extractErr error + injectErr error + }{ + { + name: "support for propagation.TextMapCarrier", + injectCarrierType: ot.TextMap, + injectCarrier: tmc, + extractCarrierType: ot.TextMap, + extractCarrier: tmc, + }, + { + name: "support for opentracing.TextMapReader and opentracing.TextMapWriter", + injectCarrierType: ot.TextMap, + injectCarrier: otTextMap, + extractCarrierType: ot.TextMap, + extractCarrier: otTextMap, + }, + { + name: "support for HTTPHeaders", + injectCarrierType: ot.HTTPHeaders, + injectCarrier: httpHeader, + extractCarrierType: ot.HTTPHeaders, + extractCarrier: httpHeader, + }, + { + name: "support for opentracing.TextMapReader and opentracing.TextMapWriter,non-same instance", + injectCarrierType: ot.TextMap, + injectCarrier: newTestTextMapWriter(&shareMap), + extractCarrierType: ot.TextMap, + extractCarrier: newTestTextMapReader(&shareMap), + }, + { + name: "inject: format type is HTTPHeaders, but carrier is not HTTPHeadersCarrier", + injectCarrierType: ot.HTTPHeaders, + injectCarrier: struct{}{}, + injectErr: ot.ErrInvalidCarrier, + }, + { + name: "extract: format type is HTTPHeaders, but carrier is not HTTPHeadersCarrier", + injectCarrierType: ot.HTTPHeaders, + injectCarrier: httpHeader, + extractCarrierType: ot.HTTPHeaders, + extractCarrier: struct{}{}, + extractErr: ot.ErrInvalidCarrier, + }, + { + name: "inject: format type is TextMap, but carrier is cannot be wrapped into propagation.TextMapCarrier", + injectCarrierType: ot.TextMap, + injectCarrier: struct{}{}, + injectErr: ot.ErrInvalidCarrier, + }, + { + name: "extract: format type is TextMap, but carrier is cannot be wrapped into propagation.TextMapCarrier", + injectCarrierType: ot.TextMap, + injectCarrier: otTextMap, + extractCarrierType: ot.TextMap, + extractCarrier: struct{}{}, + extractErr: ot.ErrInvalidCarrier, + }, + { + name: "inject: unsupported format type", + injectCarrierType: ot.Binary, + injectErr: ot.ErrUnsupportedFormat, + }, + { + name: "extract: unsupported format type", + injectCarrierType: ot.TextMap, + injectCarrier: otTextMap, + extractCarrierType: ot.Binary, + extractCarrier: struct{}{}, + extractErr: ot.ErrUnsupportedFormat, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := bridge.Inject(newBridgeSpanContext(trace.NewSpanContext(trace.SpanContextConfig{ + TraceID: [16]byte{byte(1)}, + SpanID: [8]byte{byte(2)}, + }), nil), tc.injectCarrierType, tc.injectCarrier) + assert.Equal(t, tc.injectErr, err) + + if tc.injectErr == nil { + spanContext, err := bridge.Extract(tc.extractCarrierType, tc.extractCarrier) + assert.Equal(t, tc.extractErr, err) + + if tc.extractErr == nil { + bsc, ok := spanContext.(*bridgeSpanContext) + assert.True(t, ok) + + assert.Equal(t, spanID.String(), bsc.otelSpanContext.SpanID().String()) + assert.Equal(t, traceID.String(), bsc.otelSpanContext.TraceID().String()) + } + } + }) + } +} diff --git a/bridge/opentracing/go.mod b/bridge/opentracing/go.mod index ef802c32103..765d1bad47f 100644 --- a/bridge/opentracing/go.mod +++ b/bridge/opentracing/go.mod @@ -6,13 +6,17 @@ replace go.opentelemetry.io/otel => ../.. require ( github.com/opentracing/opentracing-go v1.2.0 + github.com/stretchr/testify v1.7.2 go.opentelemetry.io/otel v1.7.0 go.opentelemetry.io/otel/trace v1.7.0 ) require ( + github.com/davecgh/go-spew v1.1.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/otel/trace => ../../trace diff --git a/bridge/opentracing/go.sum b/bridge/opentracing/go.sum index 5ec9e745497..4814eca5ba9 100644 --- a/bridge/opentracing/go.sum +++ b/bridge/opentracing/go.sum @@ -13,8 +13,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/example/otel-collector/go.mod b/example/otel-collector/go.mod index 502d4f1d4f6..536a5f99ad1 100644 --- a/example/otel-collector/go.mod +++ b/example/otel-collector/go.mod @@ -23,7 +23,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect - go.opentelemetry.io/proto/otlp v0.16.0 // indirect + go.opentelemetry.io/proto/otlp v0.18.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/text v0.3.5 // indirect diff --git a/example/otel-collector/go.sum b/example/otel-collector/go.sum index 4d8dc9f83af..574b556389c 100644 --- a/example/otel-collector/go.sum +++ b/example/otel-collector/go.sum @@ -162,8 +162,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= -go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= +go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/example/otel-collector/main.go b/example/otel-collector/main.go index c3372ab482a..7720e96f650 100644 --- a/example/otel-collector/main.go +++ b/example/otel-collector/main.go @@ -58,6 +58,8 @@ func initProvider() (func(context.Context) error, error) { // `localhost:30080` endpoint. Otherwise, replace `localhost` with the // endpoint of your cluster. If you run the app inside k8s, then you can // probably connect directly to the service through dns + ctx, cancel := context.WithTimeout(ctx, time.Second) + defer cancel() conn, err := grpc.DialContext(ctx, "localhost:30080", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) if err != nil { return nil, fmt.Errorf("failed to create gRPC connection to collector: %w", err) diff --git a/exporters/jaeger/jaeger.go b/exporters/jaeger/jaeger.go index d9b58ec4f82..d6d2fcfbbee 100644 --- a/exporters/jaeger/jaeger.go +++ b/exporters/jaeger/jaeger.go @@ -142,10 +142,10 @@ func spanToThrift(ss sdktrace.ReadOnlySpan) *gen.Span { } } - if il := ss.InstrumentationLibrary(); il.Name != "" { - tags = append(tags, getStringTag(keyInstrumentationLibraryName, il.Name)) - if il.Version != "" { - tags = append(tags, getStringTag(keyInstrumentationLibraryVersion, il.Version)) + if is := ss.InstrumentationScope(); is.Name != "" { + tags = append(tags, getStringTag(keyInstrumentationLibraryName, is.Name)) + if is.Version != "" { + tags = append(tags, getStringTag(keyInstrumentationLibraryVersion, is.Version)) } } diff --git a/exporters/otlp/otlptrace/go.mod b/exporters/otlp/otlptrace/go.mod index 1046997b7a6..f4cbc831a3d 100644 --- a/exporters/otlp/otlptrace/go.mod +++ b/exporters/otlp/otlptrace/go.mod @@ -9,7 +9,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 go.opentelemetry.io/otel/sdk v1.7.0 go.opentelemetry.io/otel/trace v1.7.0 - go.opentelemetry.io/proto/otlp v0.16.0 + go.opentelemetry.io/proto/otlp v0.18.0 google.golang.org/grpc v1.46.2 google.golang.org/protobuf v1.28.0 ) diff --git a/exporters/otlp/otlptrace/go.sum b/exporters/otlp/otlptrace/go.sum index 212a83e8ee3..a8fc336d443 100644 --- a/exporters/otlp/otlptrace/go.sum +++ b/exporters/otlp/otlptrace/go.sum @@ -163,8 +163,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= -go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= +go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go b/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go index 213f9f92a4e..7aaec38d22a 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/instrumentation.go @@ -19,8 +19,8 @@ import ( commonpb "go.opentelemetry.io/proto/otlp/common/v1" ) -func InstrumentationScope(il instrumentation.Library) *commonpb.InstrumentationScope { - if il == (instrumentation.Library{}) { +func InstrumentationScope(il instrumentation.Scope) *commonpb.InstrumentationScope { + if il == (instrumentation.Scope{}) { return nil } return &commonpb.InstrumentationScope{ diff --git a/exporters/otlp/otlptrace/internal/tracetransform/span.go b/exporters/otlp/otlptrace/internal/tracetransform/span.go index 0e8d00a0494..b83cbd72478 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/span.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/span.go @@ -34,7 +34,7 @@ func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans { type key struct { r attribute.Distinct - il instrumentation.Library + is instrumentation.Scope } ssm := make(map[key]*tracepb.ScopeSpans) @@ -47,15 +47,15 @@ func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans { rKey := sd.Resource().Equivalent() k := key{ r: rKey, - il: sd.InstrumentationLibrary(), + is: sd.InstrumentationScope(), } scopeSpan, iOk := ssm[k] if !iOk { - // Either the resource or instrumentation library were unknown. + // Either the resource or instrumentation scope were unknown. scopeSpan = &tracepb.ScopeSpans{ - Scope: InstrumentationScope(sd.InstrumentationLibrary()), + Scope: InstrumentationScope(sd.InstrumentationScope()), Spans: []*tracepb.Span{}, - SchemaUrl: sd.InstrumentationLibrary().SchemaURL, + SchemaUrl: sd.InstrumentationScope().SchemaURL, } } scopeSpan.Spans = append(scopeSpan.Spans, span(sd)) diff --git a/exporters/otlp/otlptrace/internal/tracetransform/span_test.go b/exporters/otlp/otlptrace/internal/tracetransform/span_test.go index 3bb203eae80..20c23d49458 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/span_test.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/span_test.go @@ -264,7 +264,7 @@ func TestSpanData(t *testing.T) { attribute.Int64("rk2", 5), attribute.StringSlice("rk3", []string{"sv1", "sv2"}), ), - InstrumentationLibrary: instrumentation.Library{ + InstrumentationLibrary: instrumentation.Scope{ Name: "go.opentelemetry.io/test/otel", Version: "v0.0.1", SchemaURL: semconv.SchemaURL, diff --git a/exporters/otlp/otlptrace/otlptracegrpc/go.mod b/exporters/otlp/otlptrace/otlptracegrpc/go.mod index bd28d8dcf7c..c675c4a66eb 100644 --- a/exporters/otlp/otlptrace/otlptracegrpc/go.mod +++ b/exporters/otlp/otlptrace/otlptracegrpc/go.mod @@ -8,7 +8,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 go.opentelemetry.io/otel/sdk v1.7.0 - go.opentelemetry.io/proto/otlp v0.16.0 + go.opentelemetry.io/proto/otlp v0.18.0 go.uber.org/goleak v1.1.12 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 google.golang.org/grpc v1.46.2 diff --git a/exporters/otlp/otlptrace/otlptracegrpc/go.sum b/exporters/otlp/otlptrace/otlptracegrpc/go.sum index 3a1e26f6e76..15fe71455fe 100644 --- a/exporters/otlp/otlptrace/otlptracegrpc/go.sum +++ b/exporters/otlp/otlptrace/otlptracegrpc/go.sum @@ -164,8 +164,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= -go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= +go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/exporters/otlp/otlptrace/otlptracehttp/go.mod b/exporters/otlp/otlptrace/otlptracehttp/go.mod index 0a4943c84ea..0cbec3ba70c 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/go.mod +++ b/exporters/otlp/otlptrace/otlptracehttp/go.mod @@ -9,7 +9,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 go.opentelemetry.io/otel/sdk v1.7.0 go.opentelemetry.io/otel/trace v1.7.0 - go.opentelemetry.io/proto/otlp v0.16.0 + go.opentelemetry.io/proto/otlp v0.18.0 google.golang.org/protobuf v1.28.0 ) diff --git a/exporters/otlp/otlptrace/otlptracehttp/go.sum b/exporters/otlp/otlptrace/otlptracehttp/go.sum index 212a83e8ee3..a8fc336d443 100644 --- a/exporters/otlp/otlptrace/otlptracehttp/go.sum +++ b/exporters/otlp/otlptrace/otlptracehttp/go.sum @@ -163,8 +163,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= -go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= +go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/exporters/zipkin/model.go b/exporters/zipkin/model.go index f733651dac6..81d0fc1a706 100644 --- a/exporters/zipkin/model.go +++ b/exporters/zipkin/model.go @@ -218,10 +218,10 @@ func toZipkinTags(data tracesdk.ReadOnlySpan) map[string]string { delete(m, "error") } - if il := data.InstrumentationLibrary(); il.Name != "" { - m[keyInstrumentationLibraryName] = il.Name - if il.Version != "" { - m[keyInstrumentationLibraryVersion] = il.Version + if is := data.InstrumentationScope(); is.Name != "" { + m[keyInstrumentationLibraryName] = is.Name + if is.Version != "" { + m[keyInstrumentationLibraryVersion] = is.Version } } diff --git a/metric/instrument/asyncfloat64/asyncfloat64.go b/metric/instrument/asyncfloat64/asyncfloat64.go index 91c034fb2a0..370715f694c 100644 --- a/metric/instrument/asyncfloat64/asyncfloat64.go +++ b/metric/instrument/asyncfloat64/asyncfloat64.go @@ -45,7 +45,7 @@ type Counter interface { instrument.Asynchronous } -// UpDownCounter is an instrument that records increasing or decresing values. +// UpDownCounter is an instrument that records increasing or decreasing values. type UpDownCounter interface { // Observe records the state of the instrument. // diff --git a/metric/instrument/asyncint64/asyncint64.go b/metric/instrument/asyncint64/asyncint64.go index 9dfba553d78..41a561bc4a2 100644 --- a/metric/instrument/asyncint64/asyncint64.go +++ b/metric/instrument/asyncint64/asyncint64.go @@ -45,7 +45,7 @@ type Counter interface { instrument.Asynchronous } -// UpDownCounter is an instrument that records increasing or decresing values. +// UpDownCounter is an instrument that records increasing or decreasing values. type UpDownCounter interface { // Observe records the state of the instrument. // diff --git a/metric/instrument/config.go b/metric/instrument/config.go index 842c65336d2..8778bce1619 100644 --- a/metric/instrument/config.go +++ b/metric/instrument/config.go @@ -27,7 +27,7 @@ func (cfg Config) Description() string { return cfg.description } -// Unit describes the measurement unit for a instrument. +// Unit describes the measurement unit for an instrument. func (cfg Config) Unit() unit.Unit { return cfg.unit } diff --git a/metric/instrument/syncfloat64/syncfloat64.go b/metric/instrument/syncfloat64/syncfloat64.go index 1989292ecf8..435db1127bc 100644 --- a/metric/instrument/syncfloat64/syncfloat64.go +++ b/metric/instrument/syncfloat64/syncfloat64.go @@ -39,7 +39,7 @@ type Counter interface { instrument.Synchronous } -// UpDownCounter is an instrument that records increasing or decresing values. +// UpDownCounter is an instrument that records increasing or decreasing values. type UpDownCounter interface { // Add records a change to the counter. Add(ctx context.Context, incr float64, attrs ...attribute.KeyValue) diff --git a/metric/instrument/syncint64/syncint64.go b/metric/instrument/syncint64/syncint64.go index ee882bcd922..c77a4672860 100644 --- a/metric/instrument/syncint64/syncint64.go +++ b/metric/instrument/syncint64/syncint64.go @@ -39,7 +39,7 @@ type Counter interface { instrument.Synchronous } -// UpDownCounter is an instrument that records increasing or decresing values. +// UpDownCounter is an instrument that records increasing or decreasing values. type UpDownCounter interface { // Add records a change to the counter. Add(ctx context.Context, incr int64, attrs ...attribute.KeyValue) diff --git a/metric/internal/global/state_test.go b/metric/internal/global/state_test.go index 0ef1f80f3a4..9afd23c3cfa 100644 --- a/metric/internal/global/state_test.go +++ b/metric/internal/global/state_test.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// htmp://www.apache.org/licenses/LICENSE-2.0 +// 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, diff --git a/metric/noop.go b/metric/noop.go index 622c99ace94..e8b9a9a1458 100644 --- a/metric/noop.go +++ b/metric/noop.go @@ -43,22 +43,22 @@ func NewNoopMeter() Meter { type noopMeter struct{} -// AsyncInt64 creates a instrument that does not record any metrics. +// AsyncInt64 creates an instrument that does not record any metrics. func (noopMeter) AsyncInt64() asyncint64.InstrumentProvider { return nonrecordingAsyncInt64Instrument{} } -// AsyncFloat64 creates a instrument that does not record any metrics. +// AsyncFloat64 creates an instrument that does not record any metrics. func (noopMeter) AsyncFloat64() asyncfloat64.InstrumentProvider { return nonrecordingAsyncFloat64Instrument{} } -// SyncInt64 creates a instrument that does not record any metrics. +// SyncInt64 creates an instrument that does not record any metrics. func (noopMeter) SyncInt64() syncint64.InstrumentProvider { return nonrecordingSyncInt64Instrument{} } -// SyncFloat64 creates a instrument that does not record any metrics. +// SyncFloat64 creates an instrument that does not record any metrics. func (noopMeter) SyncFloat64() syncfloat64.InstrumentProvider { return nonrecordingSyncFloat64Instrument{} } diff --git a/sdk/instrumentation/library.go b/sdk/instrumentation/library.go index 6f0016169e3..246873345de 100644 --- a/sdk/instrumentation/library.go +++ b/sdk/instrumentation/library.go @@ -22,12 +22,5 @@ For more information see package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation" // Library represents the instrumentation library. -type Library struct { - // Name is the name of the instrumentation library. This should be the - // Go package name of that library. - Name string - // Version is the version of the instrumentation library. - Version string - // SchemaURL of the telemetry emitted by the library. - SchemaURL string -} +// Deprecated: please use Scope instead. +type Library = Scope diff --git a/sdk/instrumentation/scope.go b/sdk/instrumentation/scope.go new file mode 100644 index 00000000000..775de40e30c --- /dev/null +++ b/sdk/instrumentation/scope.go @@ -0,0 +1,33 @@ +// 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 instrumentation provides an instrumentation scope structure to be +passed to both the OpenTelemetry Tracer and Meter components. + +For more information see +[this](https://github.com/open-telemetry/oteps/blob/main/text/0083-component.md). +*/ +package instrumentation // import "go.opentelemetry.io/otel/sdk/instrumentation" + +// Scope represents the instrumentation scope. +type Scope struct { + // Name is the name of the instrumentation scope. This should be the + // Go package name of that scope. + Name string + // Version is the version of the instrumentation scope. + Version string + // SchemaURL of the telemetry emitted by the scope. + SchemaURL string +} diff --git a/sdk/resource/export_common_unix_test.go b/sdk/resource/export_common_unix_test.go index 3b8b03cf43e..a296ff6f245 100644 --- a/sdk/resource/export_common_unix_test.go +++ b/sdk/resource/export_common_unix_test.go @@ -19,7 +19,6 @@ package resource // import "go.opentelemetry.io/otel/sdk/resource" var ( Uname = uname - CharsToString = charsToString GetFirstAvailableFile = getFirstAvailableFile ) diff --git a/sdk/resource/os_unix.go b/sdk/resource/os_unix.go index 42894a15b5c..1c84afc1852 100644 --- a/sdk/resource/os_unix.go +++ b/sdk/resource/os_unix.go @@ -18,7 +18,6 @@ package resource // import "go.opentelemetry.io/otel/sdk/resource" import ( - "bytes" "fmt" "os" @@ -69,23 +68,14 @@ func uname() (string, error) { } return fmt.Sprintf("%s %s %s %s %s", - charsToString(utsName.Sysname[:]), - charsToString(utsName.Nodename[:]), - charsToString(utsName.Release[:]), - charsToString(utsName.Version[:]), - charsToString(utsName.Machine[:]), + unix.ByteSliceToString(utsName.Sysname[:]), + unix.ByteSliceToString(utsName.Nodename[:]), + unix.ByteSliceToString(utsName.Release[:]), + unix.ByteSliceToString(utsName.Version[:]), + unix.ByteSliceToString(utsName.Machine[:]), ), nil } -// charsToString converts a C-like null-terminated char array to a Go string. -func charsToString(charArray []byte) string { - if i := bytes.IndexByte(charArray, 0); i >= 0 { - charArray = charArray[:i] - } - - return string(charArray) -} - // getFirstAvailableFile returns an *os.File of the first available // file from a list of candidate file paths. func getFirstAvailableFile(candidates []string) (*os.File, error) { diff --git a/sdk/resource/os_unix_test.go b/sdk/resource/os_unix_test.go index af6178613e1..d6522d01dd0 100644 --- a/sdk/resource/os_unix_test.go +++ b/sdk/resource/os_unix_test.go @@ -64,30 +64,6 @@ func TestUnameError(t *testing.T) { resource.SetDefaultUnameProvider() } -func TestCharsToString(t *testing.T) { - tt := []struct { - Name string - Bytes []byte - Expected string - }{ - {"Nil array", nil, ""}, - {"Empty array", []byte{}, ""}, - {"Empty string (null terminated)", []byte{0x00}, ""}, - {"Nonempty string (null terminated)", []byte{0x31, 0x32, 0x33, 0x00}, "123"}, - {"Nonempty string (non-null terminated)", []byte{0x31, 0x32, 0x33}, "123"}, - {"Nonempty string with values after null", []byte{0x31, 0x32, 0x33, 0x00, 0x34}, "123"}, - } - - for _, tc := range tt { - tc := tc - - t.Run(tc.Name, func(t *testing.T) { - result := resource.CharsToString(tc.Bytes) - require.EqualValues(t, tc.Expected, result) - }) - } -} - func TestGetFirstAvailableFile(t *testing.T) { tempDir := t.TempDir() diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index 3f526c1d3cf..eac69f34d76 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -74,7 +74,7 @@ func (cfg tracerProviderConfig) MarshalLog() interface{} { // instrumentation so it can trace operational flow through a system. type TracerProvider struct { mu sync.Mutex - namedTracer map[instrumentation.Library]*tracer + namedTracer map[instrumentation.Scope]*tracer spanProcessors atomic.Value // These fields are not protected by the lock mu. They are assumed to be @@ -110,7 +110,7 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider { o = ensureValidTracerProviderConfig(o) tp := &TracerProvider{ - namedTracer: make(map[instrumentation.Library]*tracer), + namedTracer: make(map[instrumentation.Scope]*tracer), sampler: o.sampler, idGenerator: o.idGenerator, spanLimits: o.spanLimits, @@ -141,18 +141,18 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T if name == "" { name = defaultTracerName } - il := instrumentation.Library{ + is := instrumentation.Scope{ Name: name, Version: c.InstrumentationVersion(), SchemaURL: c.SchemaURL(), } - t, ok := p.namedTracer[il] + t, ok := p.namedTracer[is] if !ok { t = &tracer{ - provider: p, - instrumentationLibrary: il, + provider: p, + instrumentationScope: is, } - p.namedTracer[il] = t + p.namedTracer[is] = t global.Info("Tracer created", "name", name, "version", c.InstrumentationVersion(), "schemaURL", c.SchemaURL()) } return t diff --git a/sdk/trace/provider_test.go b/sdk/trace/provider_test.go index 1f5d460d739..39caf5a91df 100644 --- a/sdk/trace/provider_test.go +++ b/sdk/trace/provider_test.go @@ -96,7 +96,7 @@ func TestSchemaURL(t *testing.T) { // Verify that the SchemaURL of the constructed Tracer is correctly populated. tracerStruct := tracerIface.(*tracer) - assert.EqualValues(t, schemaURL, tracerStruct.instrumentationLibrary.SchemaURL) + assert.EqualValues(t, schemaURL, tracerStruct.instrumentationScope.SchemaURL) } func TestTracerProviderSamplerConfigFromEnv(t *testing.T) { diff --git a/sdk/trace/snapshot.go b/sdk/trace/snapshot.go index 53aac61f5fe..0349b2f198e 100644 --- a/sdk/trace/snapshot.go +++ b/sdk/trace/snapshot.go @@ -26,22 +26,22 @@ import ( // snapshot is an record of a spans state at a particular checkpointed time. // It is used as a read-only representation of that state. type snapshot struct { - name string - spanContext trace.SpanContext - parent trace.SpanContext - spanKind trace.SpanKind - startTime time.Time - endTime time.Time - attributes []attribute.KeyValue - events []Event - links []Link - status Status - childSpanCount int - droppedAttributeCount int - droppedEventCount int - droppedLinkCount int - resource *resource.Resource - instrumentationLibrary instrumentation.Library + name string + spanContext trace.SpanContext + parent trace.SpanContext + spanKind trace.SpanKind + startTime time.Time + endTime time.Time + attributes []attribute.KeyValue + events []Event + links []Link + status Status + childSpanCount int + droppedAttributeCount int + droppedEventCount int + droppedLinkCount int + resource *resource.Resource + instrumentationScope instrumentation.Scope } var _ ReadOnlySpan = snapshot{} @@ -102,10 +102,16 @@ func (s snapshot) Status() Status { return s.status } +// InstrumentationScope returns information about the instrumentation +// scope that created the span. +func (s snapshot) InstrumentationScope() instrumentation.Scope { + return s.instrumentationScope +} + // InstrumentationLibrary returns information about the instrumentation // library that created the span. func (s snapshot) InstrumentationLibrary() instrumentation.Library { - return s.instrumentationLibrary + return s.instrumentationScope } // Resource returns information about the entity that produced the span. diff --git a/sdk/trace/span.go b/sdk/trace/span.go index edf456d93a7..d380c2719a7 100644 --- a/sdk/trace/span.go +++ b/sdk/trace/span.go @@ -63,8 +63,12 @@ type ReadOnlySpan interface { Events() []Event // Status returns the spans status. Status() Status + // InstrumentationScope returns information about the instrumentation + // scope that created the span. + InstrumentationScope() instrumentation.Scope // InstrumentationLibrary returns information about the instrumentation // library that created the span. + // Deprecated: please use InstrumentationScope instead. InstrumentationLibrary() instrumentation.Library // Resource returns information about the entity that produced the span. Resource() *resource.Resource @@ -584,12 +588,20 @@ func (s *recordingSpan) Status() Status { return s.status } +// InstrumentationScope returns the instrumentation.Scope associated with +// the Tracer that created this span. +func (s *recordingSpan) InstrumentationScope() instrumentation.Scope { + s.mu.Lock() + defer s.mu.Unlock() + return s.tracer.instrumentationScope +} + // InstrumentationLibrary returns the instrumentation.Library associated with // the Tracer that created this span. func (s *recordingSpan) InstrumentationLibrary() instrumentation.Library { s.mu.Lock() defer s.mu.Unlock() - return s.tracer.instrumentationLibrary + return s.tracer.instrumentationScope } // Resource returns the Resource associated with the Tracer that created this @@ -668,7 +680,7 @@ func (s *recordingSpan) snapshot() ReadOnlySpan { defer s.mu.Unlock() sd.endTime = s.endTime - sd.instrumentationLibrary = s.tracer.instrumentationLibrary + sd.instrumentationScope = s.tracer.instrumentationScope sd.name = s.name sd.parent = s.parent sd.resource = s.tracer.provider.resource diff --git a/sdk/trace/span_processor_filter_example_test.go b/sdk/trace/span_processor_filter_example_test.go index 6409bb57aaf..f5dd84e472a 100644 --- a/sdk/trace/span_processor_filter_example_test.go +++ b/sdk/trace/span_processor_filter_example_test.go @@ -67,7 +67,7 @@ func (f InstrumentationBlacklist) ForceFlush(ctx context.Context) error { return f.Next.ForceFlush(ctx) } func (f InstrumentationBlacklist) OnEnd(s ReadOnlySpan) { - if f.Blacklist != nil && f.Blacklist[s.InstrumentationLibrary().Name] { + if f.Blacklist != nil && f.Blacklist[s.InstrumentationScope().Name] { // Drop spans from this instrumentation return } diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index 7ea04a86f05..58b2c04c6e8 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -411,8 +411,8 @@ func TestSetSpanAttributesOnStart(t *testing.T) { attribute.String("key1", "value1"), attribute.String("key2", "value2"), }, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "StartSpanAttribute"}, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "StartSpanAttribute"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("SetSpanAttributesOnStart: -got +want %s", diff) @@ -666,8 +666,8 @@ func TestEvents(t *testing.T) { {Name: "foo", Attributes: []attribute.KeyValue{k1v1}}, {Name: "bar", Attributes: []attribute.KeyValue{k2v2, k3v3}}, }, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "Events"}, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "Events"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("Message Events: -got +want %s", diff) @@ -717,9 +717,9 @@ func TestEventsOverLimit(t *testing.T) { {Name: "foo", Attributes: []attribute.KeyValue{k1v1}}, {Name: "bar", Attributes: []attribute.KeyValue{k2v2, k3v3}}, }, - droppedEventCount: 2, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "EventsOverLimit"}, + droppedEventCount: 2, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "EventsOverLimit"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("Message Event over limit: -got +want %s", diff) @@ -753,11 +753,11 @@ func TestLinks(t *testing.T) { TraceID: tid, TraceFlags: 0x1, }), - parent: sc.WithRemote(true), - name: "span0", - links: []Link{{l1.SpanContext, l1.Attributes, 0}, {l2.SpanContext, l2.Attributes, 0}}, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "Links"}, + parent: sc.WithRemote(true), + name: "span0", + links: []Link{{l1.SpanContext, l1.Attributes, 0}, {l2.SpanContext, l2.Attributes, 0}}, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "Links"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("Link: -got +want %s", diff) @@ -811,9 +811,9 @@ func TestLinksOverLimit(t *testing.T) { {SpanContext: sc2, Attributes: []attribute.KeyValue{k2v2}, DroppedAttributeCount: 0}, {SpanContext: sc3, Attributes: []attribute.KeyValue{k3v3}, DroppedAttributeCount: 0}, }, - droppedLinkCount: 1, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "LinksOverLimit"}, + droppedLinkCount: 1, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "LinksOverLimit"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("Link over limit: -got +want %s", diff) @@ -861,7 +861,7 @@ func TestSetSpanStatus(t *testing.T) { Code: codes.Error, Description: "Error", }, - instrumentationLibrary: instrumentation.Library{Name: "SpanStatus"}, + instrumentationScope: instrumentation.Scope{Name: "SpanStatus"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("SetSpanStatus: -got +want %s", diff) @@ -891,7 +891,7 @@ func TestSetSpanStatusWithoutMessageWhenStatusIsNotError(t *testing.T) { Code: codes.Ok, Description: "", }, - instrumentationLibrary: instrumentation.Library{Name: "SpanStatus"}, + instrumentationScope: instrumentation.Scope{Name: "SpanStatus"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("SetSpanStatus: -got +want %s", diff) @@ -1230,7 +1230,7 @@ func TestRecordError(t *testing.T) { }, }, }, - instrumentationLibrary: instrumentation.Library{Name: "RecordError"}, + instrumentationScope: instrumentation.Scope{Name: "RecordError"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("SpanErrorOptions: -got +want %s", diff) @@ -1274,7 +1274,7 @@ func TestRecordErrorWithStackTrace(t *testing.T) { }, }, }, - instrumentationLibrary: instrumentation.Library{Name: "RecordError"}, + instrumentationScope: instrumentation.Scope{Name: "RecordError"}, } assert.Equal(t, got.spanContext, want.spanContext) @@ -1314,7 +1314,7 @@ func TestRecordErrorNil(t *testing.T) { Code: codes.Unset, Description: "", }, - instrumentationLibrary: instrumentation.Library{Name: "RecordErrorNil"}, + instrumentationScope: instrumentation.Scope{Name: "RecordErrorNil"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("SpanErrorOptions: -got +want %s", diff) @@ -1428,9 +1428,9 @@ func TestWithResource(t *testing.T) { attributes: []attribute.KeyValue{ attribute.String("key1", "value1"), }, - spanKind: trace.SpanKindInternal, - resource: tc.want, - instrumentationLibrary: instrumentation.Library{Name: "WithResource"}, + spanKind: trace.SpanKindInternal, + resource: tc.want, + instrumentationScope: instrumentation.Scope{Name: "WithResource"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("WithResource:\n -got +want %s", diff) @@ -1463,7 +1463,7 @@ func TestWithInstrumentationVersionAndSchema(t *testing.T) { parent: sc.WithRemote(true), name: "span0", spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{ + instrumentationScope: instrumentation.Scope{ Name: "WithInstrumentationVersion", Version: "v0.1.0", SchemaURL: "https://opentelemetry.io/schemas/1.2.0", @@ -1572,6 +1572,8 @@ func TestReadOnlySpan(t *testing.T) { assert.Equal(t, "", ro.Status().Description) assert.Equal(t, "ReadOnlySpan", ro.InstrumentationLibrary().Name) assert.Equal(t, "3", ro.InstrumentationLibrary().Version) + assert.Equal(t, "ReadOnlySpan", ro.InstrumentationScope().Name) + assert.Equal(t, "3", ro.InstrumentationScope().Version) assert.Equal(t, kv.Key, ro.Resource().Attributes()[0].Key) assert.Equal(t, kv.Value, ro.Resource().Attributes()[0].Value) @@ -1695,8 +1697,8 @@ func TestAddEventsWithMoreAttributesThanLimit(t *testing.T) { DroppedAttributeCount: 2, }, }, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "AddSpanEventWithOverLimitedAttributes"}, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "AddSpanEventWithOverLimitedAttributes"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("SetSpanAttributesOverLimit: -got +want %s", diff) @@ -1750,8 +1752,8 @@ func TestAddLinksWithMoreAttributesThanLimit(t *testing.T) { DroppedAttributeCount: 2, }, }, - spanKind: trace.SpanKindInternal, - instrumentationLibrary: instrumentation.Library{Name: "Links"}, + spanKind: trace.SpanKindInternal, + instrumentationScope: instrumentation.Scope{Name: "Links"}, } if diff := cmpDiff(got, want); diff != "" { t.Errorf("Link: -got +want %s", diff) diff --git a/sdk/trace/tracer.go b/sdk/trace/tracer.go index 5b8ab43be3d..f4a1f96f3d6 100644 --- a/sdk/trace/tracer.go +++ b/sdk/trace/tracer.go @@ -23,8 +23,8 @@ import ( ) type tracer struct { - provider *TracerProvider - instrumentationLibrary instrumentation.Library + provider *TracerProvider + instrumentationScope instrumentation.Scope } var _ trace.Tracer = &tracer{} diff --git a/sdk/trace/tracetest/span.go b/sdk/trace/tracetest/span.go index b5f47735c1f..bfe73de9c41 100644 --- a/sdk/trace/tracetest/span.go +++ b/sdk/trace/tracetest/span.go @@ -96,29 +96,29 @@ func SpanStubFromReadOnlySpan(ro tracesdk.ReadOnlySpan) SpanStub { DroppedLinks: ro.DroppedLinks(), ChildSpanCount: ro.ChildSpanCount(), Resource: ro.Resource(), - InstrumentationLibrary: ro.InstrumentationLibrary(), + InstrumentationLibrary: ro.InstrumentationScope(), } } // Snapshot returns a read-only copy of the SpanStub. func (s SpanStub) Snapshot() tracesdk.ReadOnlySpan { return spanSnapshot{ - name: s.Name, - spanContext: s.SpanContext, - parent: s.Parent, - spanKind: s.SpanKind, - startTime: s.StartTime, - endTime: s.EndTime, - attributes: s.Attributes, - events: s.Events, - links: s.Links, - status: s.Status, - droppedAttributes: s.DroppedAttributes, - droppedEvents: s.DroppedEvents, - droppedLinks: s.DroppedLinks, - childSpanCount: s.ChildSpanCount, - resource: s.Resource, - instrumentationLibrary: s.InstrumentationLibrary, + name: s.Name, + spanContext: s.SpanContext, + parent: s.Parent, + spanKind: s.SpanKind, + startTime: s.StartTime, + endTime: s.EndTime, + attributes: s.Attributes, + events: s.Events, + links: s.Links, + status: s.Status, + droppedAttributes: s.DroppedAttributes, + droppedEvents: s.DroppedEvents, + droppedLinks: s.DroppedLinks, + childSpanCount: s.ChildSpanCount, + resource: s.Resource, + instrumentationScope: s.InstrumentationLibrary, } } @@ -126,22 +126,22 @@ type spanSnapshot struct { // Embed the interface to implement the private method. tracesdk.ReadOnlySpan - name string - spanContext trace.SpanContext - parent trace.SpanContext - spanKind trace.SpanKind - startTime time.Time - endTime time.Time - attributes []attribute.KeyValue - events []tracesdk.Event - links []tracesdk.Link - status tracesdk.Status - droppedAttributes int - droppedEvents int - droppedLinks int - childSpanCount int - resource *resource.Resource - instrumentationLibrary instrumentation.Library + name string + spanContext trace.SpanContext + parent trace.SpanContext + spanKind trace.SpanKind + startTime time.Time + endTime time.Time + attributes []attribute.KeyValue + events []tracesdk.Event + links []tracesdk.Link + status tracesdk.Status + droppedAttributes int + droppedEvents int + droppedLinks int + childSpanCount int + resource *resource.Resource + instrumentationScope instrumentation.Scope } func (s spanSnapshot) Name() string { return s.name } @@ -159,6 +159,9 @@ func (s spanSnapshot) DroppedLinks() int { return s.droppedLinks func (s spanSnapshot) DroppedEvents() int { return s.droppedEvents } func (s spanSnapshot) ChildSpanCount() int { return s.childSpanCount } func (s spanSnapshot) Resource() *resource.Resource { return s.resource } +func (s spanSnapshot) InstrumentationScope() instrumentation.Scope { + return s.instrumentationScope +} func (s spanSnapshot) InstrumentationLibrary() instrumentation.Library { - return s.instrumentationLibrary + return s.instrumentationScope } diff --git a/website_docs/exporting_data.md b/website_docs/exporting_data.md index b1045e7a842..4b409aa574f 100644 --- a/website_docs/exporting_data.md +++ b/website_docs/exporting_data.md @@ -6,7 +6,7 @@ linkTitle: Exporting data Once you've instrumented your code, you need to get the data out in order to do anything useful with it. This page will cover the basics of the process and export pipeline. -# Sampling +## Sampling Sampling is a process that restricts the amount of traces that are generated by a system. The exact sampler you should use depends on your specific needs, but in general you should make a decision at the start of a trace, and allow the sampling decision to propagate to other services. @@ -27,7 +27,7 @@ Other samplers include: When you're in production, you should consider using the `TraceIDRatioBased` sampler with the `ParentBased` sampler. -# Resources +## Resources Resources are a special type of attribute that apply to all spans generated by a process. These should be used to represent underlying metadata about a process that's non-ephemeral - for example, the hostname of a process, or its instance ID. @@ -62,19 +62,19 @@ resources := resource.New(context.Background(), ) ``` -# OTLP Exporter +## OTLP Exporter OpenTelemetry Protocol (OTLP) export is available in the `go.opentelemetry.io/otel/exporters/otlp/otlptrace` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetrics` packages. Please find more documentation on [GitHub](https://github.com/open-telemetry/opentelemetry-go/tree/main/exporters/otlp) -# Jaeger Exporter +## Jaeger Exporter Jaeger export is available in the `go.opentelemetry.io/otel/exporters/jaeger` package. Please find more documentation on [GitHub](https://github.com/open-telemetry/opentelemetry-go/tree/main/exporters/jaeger) -# Prometheus Exporter +## Prometheus Exporter Prometheus export is available in the `go.opentelemetry.io/otel/exporters/prometheus` package. diff --git a/website_docs/getting-started.md b/website_docs/getting-started.md index 5fdf2418187..f0672a7efb4 100644 --- a/website_docs/getting-started.md +++ b/website_docs/getting-started.md @@ -134,7 +134,7 @@ goodbye The application can be exited with CTRL+C. You should see a similar output as above, if not make sure to go back and fix any errors. -# Trace Instrumentation +## Trace Instrumentation OpenTelemetry is split into two parts: an API to instrument code with, and SDKs that implement the API. To start integrating OpenTelemetry into any project, the API is used to define how telemetry is generated. To generate tracing telemetry in your application you will use the OpenTelemetry Trace API from the [`go.opentelemetry.io/otel/trace`] package. @@ -172,7 +172,7 @@ const name = "fib" Using the full-qualified package name, something that should be unique for Go packages, is the standard way to identify a [`Tracer`]. If your example package name differs, be sure to update the name you use here to match. -Everything should be in place now to start tracing your application. But first, what is a trace? And, how exactly should you build them for you application? +Everything should be in place now to start tracing your application. But first, what is a trace? And, how exactly should you build them for your application? To back up a bit, a trace is a type of telemetry that represents work being done by a service. A trace is a record of the connection(s) between participants processing a transaction, often through client/server requests processing and other forms of communication. @@ -263,7 +263,7 @@ A `Run` span will be a parent to both a `Poll` and `Write` span, and the `Write` Now how do you actually see the produced spans? To do this you will need to configure and install an SDK. -# SDK Installation +## SDK Installation OpenTelemetry is designed to be modular in its implementation of the OpenTelemetry API. The OpenTelemetry Go project offers an SDK package, [`go.opentelemetry.io/otel/sdk`], that implements this API and adheres to the OpenTelemetry specification. To start using this SDK you will first need to create an exporter, but before anything can happen we need to install some packages. Run the following in the `fib` directory to install the trace STDOUT exporter and the SDK. @@ -284,10 +284,11 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.10.0" ) ``` -## Creating a Console Exporter +### Creating a Console Exporter The SDK connects telemetry from the OpenTelemetry API to exporters. Exporters are packages that allow telemetry data to be emitted somewhere - either to the console (which is what we're doing here), or to a remote system or collector for further analysis and/or enrichment. OpenTelemetry supports a variety of exporters through its ecosystem including popular open source tools like [Jaeger](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/jaeger), [Zipkin](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/zipkin), and [Prometheus](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/prometheus). @@ -308,7 +309,7 @@ func newExporter(w io.Writer) (trace.SpanExporter, error) { This creates a new console exporter with basic options. You will use this function later when you configure the SDK to send telemetry data to it, but first you need to make sure that data is identifiable. -## Creating a Resource +### Creating a Resource Telemetry data can be crucial to solving issues with a service. The catch is, you need a way to identify what service, or even what service instance, that data is coming from. OpenTelemetry uses a [`Resource`] to represent the entity producing telemetry. Add the following function to the `main.go` file to create an appropriate [`Resource`] for the application. @@ -330,7 +331,7 @@ func newResource() *resource.Resource { Any information you would like to associate with all telemetry data the SDK handles can be added to the returned [`Resource`]. This is done by registering the [`Resource`] with the [`TracerProvider`]. Something you can now create! -## Installing a Tracer Provider +### Installing a Tracer Provider You have your application instrumented to produce telemetry data and you have an exporter to send that data to the console, but how are they connected? This is where the [`TracerProvider`] is used. It is a centralized point where instrumentation will get a [`Tracer`] from and funnels the telemetry data from these [`Tracer`]s to export pipelines. @@ -371,7 +372,7 @@ There's a fair amount going on here. First you are creating a console exporter t Do you remember in the previous instrumentation section when we used the global [`TracerProvider`] to get a [`Tracer`]? This last step, registering the [`TracerProvider`] globally, is what will connect that instrumentation's [`Tracer`] with this [`TracerProvider`]. This pattern, using a global [`TracerProvider`], is convenient, but not always appropriate. [`TracerProvider`]s can be explicitly passed to instrumentation or inferred from a context that contains a span. For this simple example using a global provider makes sense, but for more complex or distributed codebases these other ways of passing [`TracerProvider`]s may make more sense. -# Putting It All Together +## Putting It All Together You should now have a working application that produces trace telemetry data! Give it a try. @@ -387,7 +388,7 @@ goodbye A new file named `traces.txt` should be created in your working directory. All the traces created from running your application should be in there! -# (Bonus) Errors +## (Bonus) Errors At this point you have a working application and it is producing tracing telemetry data. Unfortunately, it was discovered that there is an error in the core functionality of the `fib` module. @@ -529,7 +530,7 @@ Excellent! The application no longer returns wrong values, and looking at the te ] ``` -# What's Next +## What's Next This guide has walked you through adding tracing instrumentation to an application and using a console exporter to send telemetry data to a file. There diff --git a/website_docs/manual.md b/website_docs/manual.md index 5ea73dc3394..ea88547e0d5 100644 --- a/website_docs/manual.md +++ b/website_docs/manual.md @@ -11,7 +11,7 @@ Instrumentation is the process of adding observability code to your application. To create spans, you'll need to acquire or initialize a tracer first. -### Initiallizing a new tracer +### Initializing a new tracer Ensure you have the right packages installed: