diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e5c35b5dcc..7e551679270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added + +- Add `go.opentelemetry.io/otel/bridge/opencensus.InstallTraceBridge`, which installs the OpenCensus trace bridge, and replaces `opencensus.NewTracer`. (#4567) + +### Deprecated + +- Deprecate `go.opentelemetry.io/otel/bridge/opencensus.NewTracer` in favor of `opencensus.InstallTraceBridge`. (#4567) + ## [1.19.0/0.42.0/0.0.7] 2023-09-28 This release contains the first stable release of the OpenTelemetry Go [metric SDK]. diff --git a/bridge/opencensus/config.go b/bridge/opencensus/config.go new file mode 100644 index 00000000000..26c94742fb1 --- /dev/null +++ b/bridge/opencensus/config.go @@ -0,0 +1,65 @@ +// 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 opencensus // import "go.opentelemetry.io/otel/bridge/opencensus" + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" +) + +const scopeName = "go.opentelemetry.io/otel/bridge/opencensus" + +// newTraceConfig returns a config configured with options. +func newTraceConfig(options []TraceOption) traceConfig { + conf := traceConfig{tp: otel.GetTracerProvider()} + for _, o := range options { + conf = o.apply(conf) + } + return conf +} + +type traceConfig struct { + tp trace.TracerProvider +} + +// TraceOption applies a configuration option value to an OpenCensus bridge +// Tracer. +type TraceOption interface { + apply(traceConfig) traceConfig +} + +// traceOptionFunc applies a set of options to a config. +type traceOptionFunc func(traceConfig) traceConfig + +// apply returns a config with option(s) applied. +func (o traceOptionFunc) apply(conf traceConfig) traceConfig { + return o(conf) +} + +// WithTracerProvider specifies a tracer provider to use for creating a tracer. +func WithTracerProvider(tp trace.TracerProvider) TraceOption { + return traceOptionFunc(func(conf traceConfig) traceConfig { + conf.tp = tp + return conf + }) +} + +type metricConfig struct{} + +// MetricOption applies a configuration option value to an OpenCensus bridge +// MetricProducer. +type MetricOption interface { + apply(metricConfig) metricConfig +} diff --git a/bridge/opencensus/config_test.go b/bridge/opencensus/config_test.go new file mode 100644 index 00000000000..bad2dab8019 --- /dev/null +++ b/bridge/opencensus/config_test.go @@ -0,0 +1,56 @@ +// 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 opencensus // import "go.opentelemetry.io/otel/bridge/opencensus" + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" +) + +func TestNewTraceConfig(t *testing.T) { + globalTP := trace.NewNoopTracerProvider() + customTP := trace.NewNoopTracerProvider() + otel.SetTracerProvider(globalTP) + for _, tc := range []struct { + desc string + opts []TraceOption + expected traceConfig + }{ + { + desc: "default", + expected: traceConfig{ + tp: globalTP, + }, + }, + { + desc: "overridden", + opts: []TraceOption{ + WithTracerProvider(customTP), + }, + expected: traceConfig{ + tp: customTP, + }, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + cfg := newTraceConfig(tc.opts) + assert.Equal(t, tc.expected, cfg) + }) + } +} diff --git a/bridge/opencensus/metric.go b/bridge/opencensus/metric.go index 1c2496d8c9b..d11b1de21ba 100644 --- a/bridge/opencensus/metric.go +++ b/bridge/opencensus/metric.go @@ -26,15 +26,13 @@ import ( "go.opentelemetry.io/otel/sdk/metric/metricdata" ) -const scopeName = "go.opentelemetry.io/otel/bridge/opencensus" - type producer struct { manager *metricproducer.Manager } // NewMetricProducer returns a metric.Producer that fetches metrics from // OpenCensus. -func NewMetricProducer() metric.Producer { +func NewMetricProducer(opts ...MetricOption) metric.Producer { return &producer{ manager: metricproducer.GlobalManager(), } diff --git a/bridge/opencensus/test/bridge_test.go b/bridge/opencensus/test/bridge_test.go index 5a278be0dfe..98041025c60 100644 --- a/bridge/opencensus/test/bridge_test.go +++ b/bridge/opencensus/test/bridge_test.go @@ -33,7 +33,7 @@ func TestMixedAPIs(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) tracer := tp.Tracer("mixedapitracer") - octrace.DefaultTracer = ocbridge.NewTracer(tracer) + ocbridge.InstallTraceBridge(ocbridge.WithTracerProvider(tp)) func() { ctx := context.Background() @@ -77,7 +77,7 @@ func TestMixedAPIs(t *testing.T) { func TestStartOptions(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) - octrace.DefaultTracer = ocbridge.NewTracer(tp.Tracer("startoptionstracer")) + ocbridge.InstallTraceBridge(ocbridge.WithTracerProvider(tp)) ctx := context.Background() _, span := octrace.StartSpan(ctx, "OpenCensusSpan", octrace.WithSpanKind(octrace.SpanKindClient)) @@ -97,8 +97,8 @@ func TestStartOptions(t *testing.T) { func TestStartSpanWithRemoteParent(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) + ocbridge.InstallTraceBridge(ocbridge.WithTracerProvider(tp)) tracer := tp.Tracer("remoteparent") - octrace.DefaultTracer = ocbridge.NewTracer(tracer) ctx := context.Background() ctx, parent := tracer.Start(ctx, "OpenTelemetrySpan1") @@ -120,8 +120,8 @@ func TestStartSpanWithRemoteParent(t *testing.T) { func TestToFromContext(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) + ocbridge.InstallTraceBridge(ocbridge.WithTracerProvider(tp)) tracer := tp.Tracer("tofromcontext") - octrace.DefaultTracer = ocbridge.NewTracer(tracer) func() { ctx := context.Background() @@ -159,7 +159,7 @@ func TestToFromContext(t *testing.T) { func TestIsRecordingEvents(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) - octrace.DefaultTracer = ocbridge.NewTracer(tp.Tracer("isrecordingevents")) + ocbridge.InstallTraceBridge(ocbridge.WithTracerProvider(tp)) ctx := context.Background() _, ocspan := octrace.StartSpan(ctx, "OpenCensusSpan1") @@ -179,7 +179,7 @@ func attrsMap(s []attribute.KeyValue) map[attribute.Key]attribute.Value { func TestSetThings(t *testing.T) { sr := tracetest.NewSpanRecorder() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) - octrace.DefaultTracer = ocbridge.NewTracer(tp.Tracer("setthings")) + ocbridge.InstallTraceBridge(ocbridge.WithTracerProvider(tp)) ctx := context.Background() _, ocspan := octrace.StartSpan(ctx, "OpenCensusSpan1") diff --git a/bridge/opencensus/trace.go b/bridge/opencensus/trace.go index 7e6f31202d6..1c45e975cfd 100644 --- a/bridge/opencensus/trace.go +++ b/bridge/opencensus/trace.go @@ -26,10 +26,21 @@ import ( // NewTracer returns an implementation of the OpenCensus Tracer interface which // uses OpenTelemetry APIs. Using this implementation of Tracer "upgrades" // libraries that use OpenCensus to OpenTelemetry to facilitate a migration. +// +// Deprecated: Use InstallTraceBridge instead. func NewTracer(tracer trace.Tracer) octrace.Tracer { return internal.NewTracer(tracer) } +// InstallTraceBridge installs the OpenCensus trace bridge, which overwrites +// the global OpenCensus tracer implementation. Once the bridge is installed, +// spans recorded using OpenCensus are redirected to the OpenTelemetry SDK. +func InstallTraceBridge(opts ...TraceOption) { + cfg := newTraceConfig(opts) + tracer := cfg.tp.Tracer(scopeName) + octrace.DefaultTracer = internal.NewTracer(tracer) +} + // OTelSpanContextToOC converts from an OpenTelemetry SpanContext to an // OpenCensus SpanContext, and handles any incompatibilities with the global // error handler. diff --git a/example/opencensus/main.go b/example/opencensus/main.go index c9709bad37a..4d1d1d04beb 100644 --- a/example/opencensus/main.go +++ b/example/opencensus/main.go @@ -78,8 +78,7 @@ func tracing(otExporter sdktrace.SpanExporter) { otel.SetTracerProvider(tp) log.Println("Installing the OpenCensus bridge to make OpenCensus libraries write spans using OpenTelemetry.") - tracer := tp.Tracer("simple") - octrace.DefaultTracer = opencensus.NewTracer(tracer) + opencensus.InstallTraceBridge() tp.ForceFlush(ctx) log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdouttrace exporter.\n-- It should have no parent, since it is the first span.") @@ -88,7 +87,7 @@ func tracing(otExporter sdktrace.SpanExporter) { tp.ForceFlush(ctx) log.Println("Creating OpenTelemetry span\n-- It should have the OpenCensus span as a parent, since the OpenCensus span was written with using OpenTelemetry APIs.") - ctx, otspan := tracer.Start(ctx, "OpenTelemetrySpan") + ctx, otspan := tp.Tracer("simple").Start(ctx, "OpenTelemetrySpan") otspan.End() tp.ForceFlush(ctx)