diff --git a/CHANGELOG.md b/CHANGELOG.md index 9021fa522..5bc75bb01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The `IsEmpty` method is added to the `Instrument` type in `go.opentelemetry.io/otel/sdk/metric`. This method is used to check if an `Instrument` instance is a zero-value. (#5431) +### Changed + +- `Tracer.Start` in `go.opentelemetry.io/otel/trace/noop` no longer allocates a span for empty span context. (#5457) + ### Fixed - Log a warning to the OpenTelemetry internal logger when a `Record` in `go.opentelemetry.io/otel/sdk/log` drops an attribute due to a limit being reached. (#5376) diff --git a/trace/noop/noop.go b/trace/noop/noop.go index 1dfa52c52..64a4f1b36 100644 --- a/trace/noop/noop.go +++ b/trace/noop/noop.go @@ -67,11 +67,13 @@ func (t Tracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) span = Span{sc: sc} } else { // No parent, return a No-Op span with an empty span context. - span = Span{} + span = noopSpanInstance } return trace.ContextWithSpan(ctx, span), span } +var noopSpanInstance trace.Span = Span{} + // Span is an OpenTelemetry No-Op Span. type Span struct { embedded.Span diff --git a/trace/noop/noop_test.go b/trace/noop/noop_test.go index c228ad099..a8eedb777 100644 --- a/trace/noop/noop_test.go +++ b/trace/noop/noop_test.go @@ -101,6 +101,19 @@ func TestTracerStartPropagatesSpanContext(t *testing.T) { assert.False(t, span.IsRecording(), "recording span returned") } +func BenchmarkNoopInstance(b *testing.B) { + tracer := NewTracerProvider().Tracer("") + ctx := trace.ContextWithSpanContext(context.Background(), trace.SpanContext{}) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, span := tracer.Start(ctx, "") + span.End() + } +} + type recordingSpan struct{ Span } func (recordingSpan) IsRecording() bool { return true }