You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	Add embedded package to trace API (#4620)
* Add trace/embedded * Update trace impl to use trace/embedded * Add noop pkg to replace no-op impl in trace pkg * Use trace/embedded in global impl * Use trace/embedded in SDK impl * Update opencensus bridge * Update opentracing bridge * Add changes to changelog * Update trace/doc.go Co-authored-by: David Ashpole <dashpole@google.com> --------- Co-authored-by: David Ashpole <dashpole@google.com>
This commit is contained in:
		
							
								
								
									
										16
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -12,16 +12,32 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | ||||
|  | ||||
| - Add `go.opentelemetry.io/otel/bridge/opencensus.InstallTraceBridge`, which installs the OpenCensus trace bridge, and replaces `opencensus.NewTracer`. (#4567) | ||||
| - Add scope version to trace and metric bridges in `go.opentelemetry.io/otel/bridge/opencensus`. (#4584) | ||||
| - Add the `go.opentelemetry.io/otel/trace/embedded` package to be embedded in the exported trace API interfaces. (#4620) | ||||
| - Add the `go.opentelemetry.io/otel/trace/noop` package as a default no-op implementation of the trace API. (#4620) | ||||
| - Add context propagation in `go.opentelemetry.io/otel/example/dice`. (#4644) | ||||
|  | ||||
| ### Deprecated | ||||
|  | ||||
| - Deprecate `go.opentelemetry.io/otel/bridge/opencensus.NewTracer` in favor of `opencensus.InstallTraceBridge`. (#4567) | ||||
| - Deprecate `go.opentelemetry.io/otel/example/fib` package is in favor of `go.opentelemetry.io/otel/example/dice`. (#4618) | ||||
| - Deprecate `go.opentelemetry.io/otel/trace.NewNoopTracerProvider`. | ||||
|   Use the added `NewTracerProvider` function in `go.opentelemetry.io/otel/trace/noop` instead. (#4620) | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - `go.opentelemetry.io/otel/bridge/opencensus.NewMetricProducer` returns a `*MetricProducer` struct instead of the metric.Producer interface. (#4583) | ||||
| - The `TracerProvider` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.TracerProvider` type. | ||||
|   This extends the `TracerProvider` interface and is is a breaking change for any existing implementation. | ||||
|   Implementors need to update their implementations based on what they want the default behavior of the interface to be. | ||||
|   See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more informatoin about how to accomplish this. (#4620) | ||||
| - The `Tracer` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.Tracer` type. | ||||
|   This extends the `Tracer` interface and is is a breaking change for any existing implementation. | ||||
|   Implementors need to update their implementations based on what they want the default behavior of the interface to be. | ||||
|   See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more informatoin about how to accomplish this. (#4620) | ||||
| - The `Span` in `go.opentelemetry.io/otel/trace` now embeds the `go.opentelemetry.io/otel/trace/embedded.Span` type. | ||||
|   This extends the `Span` interface and is is a breaking change for any existing implementation. | ||||
|   Implementors need to update their implementations based on what they want the default behavior of the interface to be. | ||||
|   See the "API Implementations" section of the `go.opentelemetry.io/otel/trace` package documentation for more informatoin about how to accomplish this. (#4620) | ||||
|  | ||||
| ## [1.19.0/0.42.0/0.0.7] 2023-09-28 | ||||
|  | ||||
|   | ||||
| @@ -20,12 +20,12 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| func TestNewTraceConfig(t *testing.T) { | ||||
| 	globalTP := trace.NewNoopTracerProvider() | ||||
| 	customTP := trace.NewNoopTracerProvider() | ||||
| 	globalTP := noop.NewTracerProvider() | ||||
| 	customTP := noop.NewTracerProvider() | ||||
| 	otel.SetTracerProvider(globalTP) | ||||
| 	for _, tc := range []struct { | ||||
| 		desc     string | ||||
|   | ||||
| @@ -24,6 +24,8 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel" | ||||
| 	"go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| type handler struct{ err error } | ||||
| @@ -38,6 +40,8 @@ func withHandler() (*handler, func()) { | ||||
| } | ||||
|  | ||||
| type tracer struct { | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	ctx  context.Context | ||||
| 	name string | ||||
| 	opts []trace.SpanStartOption | ||||
| @@ -45,8 +49,8 @@ type tracer struct { | ||||
|  | ||||
| func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { | ||||
| 	t.ctx, t.name, t.opts = ctx, name, opts | ||||
| 	noop := trace.NewNoopTracerProvider().Tracer("testing") | ||||
| 	return noop.Start(ctx, name, opts...) | ||||
| 	sub := noop.NewTracerProvider().Tracer("testing") | ||||
| 	return sub.Start(ctx, name, opts...) | ||||
| } | ||||
|  | ||||
| type ctxKey string | ||||
| @@ -110,11 +114,11 @@ func TestTracerFromContext(t *testing.T) { | ||||
| 	}) | ||||
| 	ctx := trace.ContextWithSpanContext(context.Background(), sc) | ||||
|  | ||||
| 	noop := trace.NewNoopTracerProvider().Tracer("TestTracerFromContext") | ||||
| 	tracer := noop.NewTracerProvider().Tracer("TestTracerFromContext") | ||||
| 	// Test using the fact that the No-Op span will propagate a span context . | ||||
| 	ctx, _ = noop.Start(ctx, "test") | ||||
| 	ctx, _ = tracer.Start(ctx, "test") | ||||
|  | ||||
| 	got := internal.NewTracer(noop).FromContext(ctx).SpanContext() | ||||
| 	got := internal.NewTracer(tracer).FromContext(ctx).SpanContext() | ||||
| 	// Do not test the convedsion, only that the propagtion. | ||||
| 	want := otel2oc.SpanContext(sc) | ||||
| 	if got != want { | ||||
| @@ -129,11 +133,11 @@ func TestTracerNewContext(t *testing.T) { | ||||
| 	}) | ||||
| 	ctx := trace.ContextWithSpanContext(context.Background(), sc) | ||||
|  | ||||
| 	noop := trace.NewNoopTracerProvider().Tracer("TestTracerNewContext") | ||||
| 	tracer := noop.NewTracerProvider().Tracer("TestTracerNewContext") | ||||
| 	// Test using the fact that the No-Op span will propagate a span context . | ||||
| 	_, s := noop.Start(ctx, "test") | ||||
| 	_, s := tracer.Start(ctx, "test") | ||||
|  | ||||
| 	ocTracer := internal.NewTracer(noop) | ||||
| 	ocTracer := internal.NewTracer(tracer) | ||||
| 	ctx = ocTracer.NewContext(context.Background(), internal.NewSpan(s)) | ||||
| 	got := trace.SpanContextFromContext(ctx) | ||||
|  | ||||
|   | ||||
| @@ -33,10 +33,11 @@ import ( | ||||
| 	iBaggage "go.opentelemetry.io/otel/internal/baggage" | ||||
| 	"go.opentelemetry.io/otel/propagation" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	noopTracer = trace.NewNoopTracerProvider().Tracer("") | ||||
| 	noopTracer = noop.NewTracerProvider().Tracer("") | ||||
| 	noopSpan   = func() trace.Span { | ||||
| 		_, s := noopTracer.Start(context.Background(), "") | ||||
| 		return s | ||||
|   | ||||
| @@ -26,6 +26,8 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/codes" | ||||
| 	semconv "go.opentelemetry.io/otel/semconv/v1.21.0" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| //nolint:revive // ignoring missing comments for unexported global variables in an internal package. | ||||
| @@ -44,6 +46,8 @@ type MockContextKeyValue struct { | ||||
| } | ||||
|  | ||||
| type MockTracer struct { | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	FinishedSpans         []*MockSpan | ||||
| 	SpareTraceIDs         []trace.TraceID | ||||
| 	SpareSpanIDs          []trace.SpanID | ||||
| @@ -184,6 +188,8 @@ type MockEvent struct { | ||||
| } | ||||
|  | ||||
| type MockSpan struct { | ||||
| 	embedded.Span | ||||
|  | ||||
| 	mockTracer     *MockTracer | ||||
| 	officialTracer trace.Tracer | ||||
| 	spanContext    trace.SpanContext | ||||
| @@ -295,4 +301,4 @@ func (s *MockSpan) OverrideTracer(tracer trace.Tracer) { | ||||
| 	s.officialTracer = tracer | ||||
| } | ||||
|  | ||||
| func (s *MockSpan) TracerProvider() trace.TracerProvider { return trace.NewNoopTracerProvider() } | ||||
| func (s *MockSpan) TracerProvider() trace.TracerProvider { return noop.NewTracerProvider() } | ||||
|   | ||||
| @@ -18,11 +18,14 @@ import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| // TracerProvider is an OpenTelemetry TracerProvider that wraps an OpenTracing | ||||
| // Tracer. | ||||
| type TracerProvider struct { | ||||
| 	embedded.TracerProvider | ||||
|  | ||||
| 	bridge   *BridgeTracer | ||||
| 	provider trace.TracerProvider | ||||
|  | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/bridge/opentracing/internal" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| type namedMockTracer struct { | ||||
| @@ -26,7 +27,7 @@ type namedMockTracer struct { | ||||
| 	*internal.MockTracer | ||||
| } | ||||
|  | ||||
| type namedMockTracerProvider struct{} | ||||
| type namedMockTracerProvider struct{ embedded.TracerProvider } | ||||
|  | ||||
| var _ trace.TracerProvider = (*namedMockTracerProvider)(nil) | ||||
|  | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/bridge/opentracing/migration" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| // WrapperTracerProvider is an OpenTelemetry TracerProvider that wraps an | ||||
| @@ -26,6 +27,8 @@ import ( | ||||
| // | ||||
| // Deprecated: Use the TracerProvider from NewTracerProvider(...) instead. | ||||
| type WrapperTracerProvider struct { | ||||
| 	embedded.TracerProvider | ||||
|  | ||||
| 	wTracer *WrapperTracer | ||||
| } | ||||
|  | ||||
| @@ -56,6 +59,8 @@ func NewWrappedTracerProvider(bridge *BridgeTracer, tracer trace.Tracer) *Wrappe | ||||
| // aware how to operate in environment where OpenTracing API is also | ||||
| // used. | ||||
| type WrapperTracer struct { | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	bridge *BridgeTracer | ||||
| 	tracer trace.Tracer | ||||
| } | ||||
|   | ||||
| @@ -20,9 +20,10 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/metric" | ||||
| 	"go.opentelemetry.io/otel/metric/noop" | ||||
| 	metricnoop "go.opentelemetry.io/otel/metric/noop" | ||||
| 	"go.opentelemetry.io/otel/propagation" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	tracenoop "go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| type nonComparableTracerProvider struct { | ||||
| @@ -55,7 +56,7 @@ func TestSetTracerProvider(t *testing.T) { | ||||
| 	t.Run("First Set() should replace the delegate", func(t *testing.T) { | ||||
| 		ResetForTest(t) | ||||
|  | ||||
| 		SetTracerProvider(trace.NewNoopTracerProvider()) | ||||
| 		SetTracerProvider(tracenoop.NewTracerProvider()) | ||||
|  | ||||
| 		_, ok := TracerProvider().(*tracerProvider) | ||||
| 		if ok { | ||||
| @@ -67,7 +68,7 @@ func TestSetTracerProvider(t *testing.T) { | ||||
| 		ResetForTest(t) | ||||
|  | ||||
| 		tp := TracerProvider() | ||||
| 		SetTracerProvider(trace.NewNoopTracerProvider()) | ||||
| 		SetTracerProvider(tracenoop.NewTracerProvider()) | ||||
|  | ||||
| 		ntp := tp.(*tracerProvider) | ||||
|  | ||||
| @@ -153,7 +154,7 @@ func TestSetMeterProvider(t *testing.T) { | ||||
| 	t.Run("First Set() should replace the delegate", func(t *testing.T) { | ||||
| 		ResetForTest(t) | ||||
|  | ||||
| 		SetMeterProvider(noop.NewMeterProvider()) | ||||
| 		SetMeterProvider(metricnoop.NewMeterProvider()) | ||||
|  | ||||
| 		_, ok := MeterProvider().(*meterProvider) | ||||
| 		if ok { | ||||
| @@ -166,7 +167,7 @@ func TestSetMeterProvider(t *testing.T) { | ||||
|  | ||||
| 		mp := MeterProvider() | ||||
|  | ||||
| 		SetMeterProvider(noop.NewMeterProvider()) | ||||
| 		SetMeterProvider(metricnoop.NewMeterProvider()) | ||||
|  | ||||
| 		dmp := mp.(*meterProvider) | ||||
|  | ||||
|   | ||||
| @@ -39,6 +39,7 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/codes" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| // tracerProvider is a placeholder for a configured SDK TracerProvider. | ||||
| @@ -46,6 +47,8 @@ import ( | ||||
| // All TracerProvider functionality is forwarded to a delegate once | ||||
| // configured. | ||||
| type tracerProvider struct { | ||||
| 	embedded.TracerProvider | ||||
|  | ||||
| 	mtx      sync.Mutex | ||||
| 	tracers  map[il]*tracer | ||||
| 	delegate trace.TracerProvider | ||||
| @@ -119,6 +122,8 @@ type il struct { | ||||
| // All Tracer functionality is forwarded to a delegate once configured. | ||||
| // Otherwise, all functionality is forwarded to a NoopTracer. | ||||
| type tracer struct { | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	name     string | ||||
| 	opts     []trace.TracerOption | ||||
| 	provider *tracerProvider | ||||
| @@ -156,6 +161,8 @@ func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStart | ||||
| // SpanContext. It performs no operations other than to return the wrapped | ||||
| // SpanContext. | ||||
| type nonRecordingSpan struct { | ||||
| 	embedded.Span | ||||
|  | ||||
| 	sc     trace.SpanContext | ||||
| 	tracer *tracer | ||||
| } | ||||
|   | ||||
| @@ -23,9 +23,13 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| type fnTracerProvider struct { | ||||
| 	embedded.TracerProvider | ||||
|  | ||||
| 	tracer func(string, ...trace.TracerOption) trace.Tracer | ||||
| } | ||||
|  | ||||
| @@ -34,6 +38,8 @@ func (fn fnTracerProvider) Tracer(instrumentationName string, opts ...trace.Trac | ||||
| } | ||||
|  | ||||
| type fnTracer struct { | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	start func(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) | ||||
| } | ||||
|  | ||||
| @@ -72,7 +78,7 @@ func TestTraceProviderDelegation(t *testing.T) { | ||||
| 							assert.Equal(t, want, spanName) | ||||
| 						} | ||||
| 					} | ||||
| 					return trace.NewNoopTracerProvider().Tracer(name).Start(ctx, spanName) | ||||
| 					return noop.NewTracerProvider().Tracer(name).Start(ctx, spanName) | ||||
| 				}, | ||||
| 			} | ||||
| 		}, | ||||
| @@ -107,7 +113,7 @@ func TestTraceProviderDelegates(t *testing.T) { | ||||
| 		tracer: func(name string, opts ...trace.TracerOption) trace.Tracer { | ||||
| 			called = true | ||||
| 			assert.Equal(t, "abc", name) | ||||
| 			return trace.NewNoopTracerProvider().Tracer("") | ||||
| 			return noop.NewTracerProvider().Tracer("") | ||||
| 		}, | ||||
| 	}) | ||||
|  | ||||
| @@ -148,7 +154,7 @@ func TestTraceProviderDelegatesConcurrentSafe(t *testing.T) { | ||||
| 				// Signal the goroutine to finish. | ||||
| 				close(quit) | ||||
| 			} | ||||
| 			return trace.NewNoopTracerProvider().Tracer("") | ||||
| 			return noop.NewTracerProvider().Tracer("") | ||||
| 		}, | ||||
| 	}) | ||||
|  | ||||
| @@ -195,7 +201,7 @@ func TestTracerDelegatesConcurrentSafe(t *testing.T) { | ||||
| 						// Signal the goroutine to finish. | ||||
| 						close(quit) | ||||
| 					} | ||||
| 					return trace.NewNoopTracerProvider().Tracer("").Start(ctx, spanName) | ||||
| 					return noop.NewTracerProvider().Tracer("").Start(ctx, spanName) | ||||
| 				}, | ||||
| 			} | ||||
| 		}, | ||||
| @@ -218,7 +224,7 @@ func TestTraceProviderDelegatesSameInstance(t *testing.T) { | ||||
|  | ||||
| 	SetTracerProvider(fnTracerProvider{ | ||||
| 		tracer: func(name string, opts ...trace.TracerOption) trace.Tracer { | ||||
| 			return trace.NewNoopTracerProvider().Tracer("") | ||||
| 			return noop.NewTracerProvider().Tracer("") | ||||
| 		}, | ||||
| 	}) | ||||
|  | ||||
|   | ||||
| @@ -25,6 +25,8 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/sdk/instrumentation" | ||||
| 	"go.opentelemetry.io/otel/sdk/resource" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -73,6 +75,8 @@ func (cfg tracerProviderConfig) MarshalLog() interface{} { | ||||
| // TracerProvider is an OpenTelemetry TracerProvider. It provides Tracers to | ||||
| // instrumentation so it can trace operational flow through a system. | ||||
| type TracerProvider struct { | ||||
| 	embedded.TracerProvider | ||||
|  | ||||
| 	mu             sync.Mutex | ||||
| 	namedTracer    map[instrumentation.Scope]*tracer | ||||
| 	spanProcessors atomic.Pointer[spanProcessorStates] | ||||
| @@ -139,7 +143,7 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider { | ||||
| func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { | ||||
| 	// This check happens before the mutex is acquired to avoid deadlocking if Tracer() is called from within Shutdown(). | ||||
| 	if p.isShutdown.Load() { | ||||
| 		return trace.NewNoopTracerProvider().Tracer(name, opts...) | ||||
| 		return noop.NewTracerProvider().Tracer(name, opts...) | ||||
| 	} | ||||
| 	c := trace.NewTracerConfig(opts...) | ||||
| 	if name == "" { | ||||
| @@ -157,7 +161,7 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T | ||||
| 		// Must check the flag after acquiring the mutex to avoid returning a valid tracer if Shutdown() ran | ||||
| 		// after the first check above but before we acquired the mutex. | ||||
| 		if p.isShutdown.Load() { | ||||
| 			return trace.NewNoopTracerProvider().Tracer(name, opts...), true | ||||
| 			return noop.NewTracerProvider().Tracer(name, opts...), true | ||||
| 		} | ||||
| 		t, ok := p.namedTracer[is] | ||||
| 		if !ok { | ||||
|   | ||||
| @@ -32,6 +32,7 @@ import ( | ||||
| 	"go.opentelemetry.io/otel/sdk/resource" | ||||
| 	semconv "go.opentelemetry.io/otel/semconv/v1.21.0" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| // ReadOnlySpan allows reading information from the data structure underlying a | ||||
| @@ -108,6 +109,8 @@ type ReadWriteSpan interface { | ||||
| // recordingSpan is an implementation of the OpenTelemetry Span API | ||||
| // representing the individual component of a trace that is sampled. | ||||
| type recordingSpan struct { | ||||
| 	embedded.Span | ||||
|  | ||||
| 	// mu protects the contents of this span. | ||||
| 	mu sync.Mutex | ||||
|  | ||||
| @@ -774,6 +777,8 @@ func (s *recordingSpan) runtimeTrace(ctx context.Context) context.Context { | ||||
| // that wraps a SpanContext. It performs no operations other than to return | ||||
| // the wrapped SpanContext or TracerProvider that created it. | ||||
| type nonRecordingSpan struct { | ||||
| 	embedded.Span | ||||
|  | ||||
| 	// tracer is the SDK tracer that created this span. | ||||
| 	tracer *tracer | ||||
| 	sc     trace.SpanContext | ||||
|   | ||||
| @@ -20,9 +20,12 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/sdk/instrumentation" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| type tracer struct { | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	provider             *TracerProvider | ||||
| 	instrumentationScope instrumentation.Scope | ||||
| } | ||||
|   | ||||
							
								
								
									
										64
									
								
								trace/doc.go
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								trace/doc.go
									
									
									
									
									
								
							| @@ -62,5 +62,69 @@ a default. | ||||
| 		defer span.End() | ||||
| 		// ... | ||||
| 	} | ||||
|  | ||||
| # API Implementations | ||||
|  | ||||
| This package does not conform to the standard Go versioning policy; all of its | ||||
| interfaces may have methods added to them without a package major version bump. | ||||
| This non-standard API evolution could surprise an uninformed implementation | ||||
| author. They could unknowingly build their implementation in a way that would | ||||
| result in a runtime panic for their users that update to the new API. | ||||
|  | ||||
| The API is designed to help inform an instrumentation author about this | ||||
| non-standard API evolution. It requires them to choose a default behavior for | ||||
| unimplemented interface methods. There are three behavior choices they can | ||||
| make: | ||||
|  | ||||
|   - Compilation failure | ||||
|   - Panic | ||||
|   - Default to another implementation | ||||
|  | ||||
| All interfaces in this API embed a corresponding interface from | ||||
| [go.opentelemetry.io/otel/trace/embedded]. If an author wants the default | ||||
| behavior of their implementations to be a compilation failure, signaling to | ||||
| their users they need to update to the latest version of that implementation, | ||||
| they need to embed the corresponding interface from | ||||
| [go.opentelemetry.io/otel/trace/embedded] in their implementation. For | ||||
| example, | ||||
|  | ||||
| 	import "go.opentelemetry.io/otel/trace/embedded" | ||||
|  | ||||
| 	type TracerProvider struct { | ||||
| 		embedded.TracerProvider | ||||
| 		// ... | ||||
| 	} | ||||
|  | ||||
| If an author wants the default behavior of their implementations to panic, they | ||||
| can embed the API interface directly. | ||||
|  | ||||
| 	import "go.opentelemetry.io/otel/trace" | ||||
|  | ||||
| 	type TracerProvider struct { | ||||
| 		trace.TracerProvider | ||||
| 		// ... | ||||
| 	} | ||||
|  | ||||
| This option is not recommended. It will lead to publishing packages that | ||||
| contain runtime panics when users update to newer versions of | ||||
| [go.opentelemetry.io/otel/trace], which may be done with a trasitive | ||||
| dependency. | ||||
|  | ||||
| Finally, an author can embed another implementation in theirs. The embedded | ||||
| implementation will be used for methods not defined by the author. For example, | ||||
| an author who wants to default to silently dropping the call can use | ||||
| [go.opentelemetry.io/otel/trace/noop]: | ||||
|  | ||||
| 	import "go.opentelemetry.io/otel/trace/noop" | ||||
|  | ||||
| 	type TracerProvider struct { | ||||
| 		noop.TracerProvider | ||||
| 		// ... | ||||
| 	} | ||||
|  | ||||
| It is strongly recommended that authors only embed | ||||
| [go.opentelemetry.io/otel/trace/noop] if they choose this default behavior. | ||||
| That implementation is the only one OpenTelemetry authors can guarantee will | ||||
| fully implement all the API interfaces when a user updates their API. | ||||
| */ | ||||
| package trace // import "go.opentelemetry.io/otel/trace" | ||||
|   | ||||
							
								
								
									
										56
									
								
								trace/embedded/embedded.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								trace/embedded/embedded.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 embedded provides interfaces embedded within the [OpenTelemetry | ||||
| // trace API]. | ||||
| // | ||||
| // Implementers of the [OpenTelemetry trace API] can embed the relevant type | ||||
| // from this package into their implementation directly. Doing so will result | ||||
| // in a compilation error for users when the [OpenTelemetry trace API] is | ||||
| // extended (which is something that can happen without a major version bump of | ||||
| // the API package). | ||||
| // | ||||
| // [OpenTelemetry trace API]: https://pkg.go.dev/go.opentelemetry.io/otel/trace | ||||
| package embedded // import "go.opentelemetry.io/otel/trace/embedded" | ||||
|  | ||||
| // TracerProvider is embedded in | ||||
| // [go.opentelemetry.io/otel/trace.TracerProvider]. | ||||
| // | ||||
| // Embed this interface in your implementation of the | ||||
| // [go.opentelemetry.io/otel/trace.TracerProvider] if you want users to | ||||
| // experience a compilation error, signaling they need to update to your latest | ||||
| // implementation, when the [go.opentelemetry.io/otel/trace.TracerProvider] | ||||
| // interface is extended (which is something that can happen without a major | ||||
| // version bump of the API package). | ||||
| type TracerProvider interface{ tracerProvider() } | ||||
|  | ||||
| // Tracer is embedded in [go.opentelemetry.io/otel/trace.Tracer]. | ||||
| // | ||||
| // Embed this interface in your implementation of the | ||||
| // [go.opentelemetry.io/otel/trace.Tracer] if you want users to experience a | ||||
| // compilation error, signaling they need to update to your latest | ||||
| // implementation, when the [go.opentelemetry.io/otel/trace.Tracer] interface | ||||
| // is extended (which is something that can happen without a major version bump | ||||
| // of the API package). | ||||
| type Tracer interface{ tracer() } | ||||
|  | ||||
| // Span is embedded in [go.opentelemetry.io/otel/trace.Span]. | ||||
| // | ||||
| // Embed this interface in your implementation of the | ||||
| // [go.opentelemetry.io/otel/trace.Span] if you want users to experience a | ||||
| // compilation error, signaling they need to update to your latest | ||||
| // implementation, when the [go.opentelemetry.io/otel/trace.Span] interface is | ||||
| // extended (which is something that can happen without a major version bump of | ||||
| // the API package). | ||||
| type Span interface{ span() } | ||||
| @@ -19,16 +19,20 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/codes" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| // NewNoopTracerProvider returns an implementation of TracerProvider that | ||||
| // performs no operations. The Tracer and Spans created from the returned | ||||
| // TracerProvider also perform no operations. | ||||
| // | ||||
| // Deprecated: Use [go.opentelemetry.io/otel/trace/noop.NewTracerProvider] | ||||
| // instead. | ||||
| func NewNoopTracerProvider() TracerProvider { | ||||
| 	return noopTracerProvider{} | ||||
| } | ||||
|  | ||||
| type noopTracerProvider struct{} | ||||
| type noopTracerProvider struct{ embedded.TracerProvider } | ||||
|  | ||||
| var _ TracerProvider = noopTracerProvider{} | ||||
|  | ||||
| @@ -38,7 +42,7 @@ func (p noopTracerProvider) Tracer(string, ...TracerOption) Tracer { | ||||
| } | ||||
|  | ||||
| // noopTracer is an implementation of Tracer that performs no operations. | ||||
| type noopTracer struct{} | ||||
| type noopTracer struct{ embedded.Tracer } | ||||
|  | ||||
| var _ Tracer = noopTracer{} | ||||
|  | ||||
| @@ -54,7 +58,7 @@ func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption | ||||
| } | ||||
|  | ||||
| // noopSpan is an implementation of Span that performs no operations. | ||||
| type noopSpan struct{} | ||||
| type noopSpan struct{ embedded.Span } | ||||
|  | ||||
| var _ Span = noopSpan{} | ||||
|  | ||||
|   | ||||
							
								
								
									
										118
									
								
								trace/noop/noop.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								trace/noop/noop.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| // 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 noop provides an implementation of the OpenTelemetry trace API that | ||||
| // produces no telemetry and minimizes used computation resources. | ||||
| // | ||||
| // Using this package to implement the OpenTelemetry trace API will effectively | ||||
| // disable OpenTelemetry. | ||||
| // | ||||
| // This implementation can be embedded in other implementations of the | ||||
| // OpenTelemetry trace API. Doing so will mean the implementation defaults to | ||||
| // no operation for methods it does not implement. | ||||
| package noop // import "go.opentelemetry.io/otel/trace/noop" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/codes" | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// Compile-time check this implements the OpenTelemetry API. | ||||
|  | ||||
| 	_ trace.TracerProvider = TracerProvider{} | ||||
| 	_ trace.Tracer         = Tracer{} | ||||
| 	_ trace.Span           = Span{} | ||||
| ) | ||||
|  | ||||
| // TracerProvider is an OpenTelemetry No-Op TracerProvider. | ||||
| type TracerProvider struct{ embedded.TracerProvider } | ||||
|  | ||||
| // NewTracerProvider returns a TracerProvider that does not record any telemetry. | ||||
| func NewTracerProvider() TracerProvider { | ||||
| 	return TracerProvider{} | ||||
| } | ||||
|  | ||||
| // Tracer returns an OpenTelemetry Tracer that does not record any telemetry. | ||||
| func (TracerProvider) Tracer(string, ...trace.TracerOption) trace.Tracer { | ||||
| 	return Tracer{} | ||||
| } | ||||
|  | ||||
| // Tracer is an OpenTelemetry No-Op Tracer. | ||||
| type Tracer struct{ embedded.Tracer } | ||||
|  | ||||
| // Start creates a span. The created span will be set in a child context of ctx | ||||
| // and returned with the span. | ||||
| // | ||||
| // If ctx contains a span context, the returned span will also contain that | ||||
| // span context. If the span context in ctx is for a non-recording span, that | ||||
| // span instance will be returned directly. | ||||
| func (t Tracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) (context.Context, trace.Span) { | ||||
| 	span := trace.SpanFromContext(ctx) | ||||
|  | ||||
| 	// If the parent context contains a non-zero span context, that span | ||||
| 	// context needs to be returned as a non-recording span | ||||
| 	// (https://github.com/open-telemetry/opentelemetry-specification/blob/3a1dde966a4ce87cce5adf464359fe369741bbea/specification/trace/api.md#behavior-of-the-api-in-the-absence-of-an-installed-sdk). | ||||
| 	var zeroSC trace.SpanContext | ||||
| 	if sc := span.SpanContext(); !sc.Equal(zeroSC) { | ||||
| 		if !span.IsRecording() { | ||||
| 			// If the span is not recording return it directly. | ||||
| 			return ctx, span | ||||
| 		} | ||||
| 		// Otherwise, return the span context needs in a non-recording span. | ||||
| 		span = Span{sc: sc} | ||||
| 	} else { | ||||
| 		// No parent, return a No-Op span with an empty span context. | ||||
| 		span = Span{} | ||||
| 	} | ||||
| 	return trace.ContextWithSpan(ctx, span), span | ||||
| } | ||||
|  | ||||
| // Span is an OpenTelemetry No-Op Span. | ||||
| type Span struct { | ||||
| 	embedded.Span | ||||
|  | ||||
| 	sc trace.SpanContext | ||||
| } | ||||
|  | ||||
| // SpanContext returns an empty span context. | ||||
| func (s Span) SpanContext() trace.SpanContext { return s.sc } | ||||
|  | ||||
| // IsRecording always returns false. | ||||
| func (Span) IsRecording() bool { return false } | ||||
|  | ||||
| // SetStatus does nothing. | ||||
| func (Span) SetStatus(codes.Code, string) {} | ||||
|  | ||||
| // SetAttributes does nothing. | ||||
| func (Span) SetAttributes(...attribute.KeyValue) {} | ||||
|  | ||||
| // End does nothing. | ||||
| func (Span) End(...trace.SpanEndOption) {} | ||||
|  | ||||
| // RecordError does nothing. | ||||
| func (Span) RecordError(error, ...trace.EventOption) {} | ||||
|  | ||||
| // AddEvent does nothing. | ||||
| func (Span) AddEvent(string, ...trace.EventOption) {} | ||||
|  | ||||
| // SetName does nothing. | ||||
| func (Span) SetName(string) {} | ||||
|  | ||||
| // TracerProvider returns a No-Op TracerProvider. | ||||
| func (Span) TracerProvider() trace.TracerProvider { return TracerProvider{} } | ||||
							
								
								
									
										117
									
								
								trace/noop/noop_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								trace/noop/noop_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| // 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 noop // import "go.opentelemetry.io/otel/trace/noop" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| ) | ||||
|  | ||||
| func TestImplementationNoPanics(t *testing.T) { | ||||
| 	// Check that if type has an embedded interface and that interface has | ||||
| 	// methods added to it than the No-Op implementation implements them. | ||||
| 	t.Run("TracerProvider", assertAllExportedMethodNoPanic( | ||||
| 		reflect.ValueOf(TracerProvider{}), | ||||
| 		reflect.TypeOf((*trace.TracerProvider)(nil)).Elem(), | ||||
| 	)) | ||||
| 	t.Run("Meter", assertAllExportedMethodNoPanic( | ||||
| 		reflect.ValueOf(Tracer{}), | ||||
| 		reflect.TypeOf((*trace.Tracer)(nil)).Elem(), | ||||
| 	)) | ||||
| 	t.Run("Span", assertAllExportedMethodNoPanic( | ||||
| 		reflect.ValueOf(Span{}), | ||||
| 		reflect.TypeOf((*trace.Span)(nil)).Elem(), | ||||
| 	)) | ||||
| } | ||||
|  | ||||
| func assertAllExportedMethodNoPanic(rVal reflect.Value, rType reflect.Type) func(*testing.T) { | ||||
| 	return func(t *testing.T) { | ||||
| 		for n := 0; n < rType.NumMethod(); n++ { | ||||
| 			mType := rType.Method(n) | ||||
| 			if !mType.IsExported() { | ||||
| 				t.Logf("ignoring unexported %s", mType.Name) | ||||
| 				continue | ||||
| 			} | ||||
| 			m := rVal.MethodByName(mType.Name) | ||||
| 			if !m.IsValid() { | ||||
| 				t.Errorf("unknown method for %s: %s", rVal.Type().Name(), mType.Name) | ||||
| 			} | ||||
|  | ||||
| 			numIn := mType.Type.NumIn() | ||||
| 			if mType.Type.IsVariadic() { | ||||
| 				numIn-- | ||||
| 			} | ||||
| 			args := make([]reflect.Value, numIn) | ||||
| 			ctx := context.Background() | ||||
| 			for i := range args { | ||||
| 				aType := mType.Type.In(i) | ||||
| 				if aType.Name() == "Context" { | ||||
| 					// Do not panic on a nil context. | ||||
| 					args[i] = reflect.ValueOf(ctx) | ||||
| 				} else { | ||||
| 					args[i] = reflect.New(aType).Elem() | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			assert.NotPanicsf(t, func() { | ||||
| 				_ = m.Call(args) | ||||
| 			}, "%s.%s", rVal.Type().Name(), mType.Name) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestNewTracerProvider(t *testing.T) { | ||||
| 	tp := NewTracerProvider() | ||||
| 	assert.Equal(t, tp, TracerProvider{}) | ||||
| 	tracer := tp.Tracer("") | ||||
| 	assert.Equal(t, tracer, Tracer{}) | ||||
| } | ||||
|  | ||||
| func TestTracerStartPropagatesSpanContext(t *testing.T) { | ||||
| 	tracer := NewTracerProvider().Tracer("") | ||||
| 	spanCtx := trace.SpanContext{} | ||||
|  | ||||
| 	ctx := trace.ContextWithSpanContext(context.Background(), spanCtx) | ||||
| 	ctx, span := tracer.Start(ctx, "test_span") | ||||
| 	assert.Equal(t, spanCtx, trace.SpanContextFromContext(ctx), "empty span context not set in context") | ||||
| 	assert.IsType(t, Span{}, span, "non-noop span returned") | ||||
| 	assert.Equal(t, spanCtx, span.SpanContext(), "empty span context not returned from span") | ||||
| 	assert.False(t, span.IsRecording(), "empty span context returned recording span") | ||||
|  | ||||
| 	spanCtx = spanCtx.WithTraceID(trace.TraceID([16]byte{1})) | ||||
| 	spanCtx = spanCtx.WithSpanID(trace.SpanID([8]byte{1})) | ||||
| 	ctx = trace.ContextWithSpanContext(context.Background(), spanCtx) | ||||
| 	ctx, span = tracer.Start(ctx, "test_span") | ||||
| 	assert.Equal(t, spanCtx, trace.SpanContextFromContext(ctx), "non-empty span context not set in context") | ||||
| 	assert.Equal(t, spanCtx, span.SpanContext(), "non-empty span context not returned from span") | ||||
| 	assert.False(t, span.IsRecording(), "non-empty span context returned recording span") | ||||
|  | ||||
| 	rSpan := recordingSpan{Span: Span{sc: spanCtx}} | ||||
| 	ctx = trace.ContextWithSpan(context.Background(), rSpan) | ||||
| 	ctx, span = tracer.Start(ctx, "test_span") | ||||
| 	assert.Equal(t, spanCtx, trace.SpanContextFromContext(ctx), "recording span's span context not set in context") | ||||
| 	assert.IsType(t, Span{}, span, "non-noop span returned") | ||||
| 	assert.Equal(t, spanCtx, span.SpanContext(), "recording span's span context not returned from span") | ||||
| 	assert.False(t, span.IsRecording(), "recording span returned") | ||||
| } | ||||
|  | ||||
| type recordingSpan struct{ Span } | ||||
|  | ||||
| func (recordingSpan) IsRecording() bool { return true } | ||||
| @@ -22,6 +22,7 @@ import ( | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	"go.opentelemetry.io/otel/codes" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -342,8 +343,15 @@ func (sc SpanContext) MarshalJSON() ([]byte, error) { | ||||
| // create a Span and it is then up to the operation the Span represents to | ||||
| // properly end the Span when the operation itself ends. | ||||
| // | ||||
| // Warning: methods may be added to this interface in minor releases. | ||||
| // Warning: Methods may be added to this interface in minor releases. See | ||||
| // package documentation on API implementation for information on how to set | ||||
| // default behavior for unimplemented methods. | ||||
| type Span interface { | ||||
| 	// Users of the interface can ignore this. This embedded type is only used | ||||
| 	// by implementations of this interface. See the "API Implementations" | ||||
| 	// section of the package documentation for more information. | ||||
| 	embedded.Span | ||||
|  | ||||
| 	// End completes the Span. The Span is considered complete and ready to be | ||||
| 	// delivered through the rest of the telemetry pipeline after this method | ||||
| 	// is called. Therefore, updates to the Span are not allowed after this | ||||
| @@ -490,8 +498,15 @@ func (sk SpanKind) String() string { | ||||
|  | ||||
| // Tracer is the creator of Spans. | ||||
| // | ||||
| // Warning: methods may be added to this interface in minor releases. | ||||
| // Warning: Methods may be added to this interface in minor releases. See | ||||
| // package documentation on API implementation for information on how to set | ||||
| // default behavior for unimplemented methods. | ||||
| type Tracer interface { | ||||
| 	// Users of the interface can ignore this. This embedded type is only used | ||||
| 	// by implementations of this interface. See the "API Implementations" | ||||
| 	// section of the package documentation for more information. | ||||
| 	embedded.Tracer | ||||
|  | ||||
| 	// Start creates a span and a context.Context containing the newly-created span. | ||||
| 	// | ||||
| 	// If the context.Context provided in `ctx` contains a Span then the newly-created | ||||
| @@ -522,8 +537,15 @@ type Tracer interface { | ||||
| // at runtime from its users or it can simply use the globally registered one | ||||
| // (see https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider). | ||||
| // | ||||
| // Warning: methods may be added to this interface in minor releases. | ||||
| // Warning: Methods may be added to this interface in minor releases. See | ||||
| // package documentation on API implementation for information on how to set | ||||
| // default behavior for unimplemented methods. | ||||
| type TracerProvider interface { | ||||
| 	// Users of the interface can ignore this. This embedded type is only used | ||||
| 	// by implementations of this interface. See the "API Implementations" | ||||
| 	// section of the package documentation for more information. | ||||
| 	embedded.TracerProvider | ||||
|  | ||||
| 	// Tracer returns a unique Tracer scoped to be used by instrumentation code | ||||
| 	// to trace computational workflows. The scope and identity of that | ||||
| 	// instrumentation code is uniquely defined by the name and options passed. | ||||
|   | ||||
| @@ -20,19 +20,21 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/trace" | ||||
| 	"go.opentelemetry.io/otel/trace/embedded" | ||||
| 	"go.opentelemetry.io/otel/trace/noop" | ||||
| ) | ||||
|  | ||||
| type testTracerProvider struct{} | ||||
| type testTracerProvider struct{ embedded.TracerProvider } | ||||
|  | ||||
| var _ trace.TracerProvider = &testTracerProvider{} | ||||
|  | ||||
| func (*testTracerProvider) Tracer(_ string, _ ...trace.TracerOption) trace.Tracer { | ||||
| 	return trace.NewNoopTracerProvider().Tracer("") | ||||
| 	return noop.NewTracerProvider().Tracer("") | ||||
| } | ||||
|  | ||||
| func TestMultipleGlobalTracerProvider(t *testing.T) { | ||||
| 	p1 := testTracerProvider{} | ||||
| 	p2 := trace.NewNoopTracerProvider() | ||||
| 	p2 := noop.NewTracerProvider() | ||||
| 	SetTracerProvider(&p1) | ||||
| 	SetTracerProvider(p2) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user