From 40478befe06126b867565dc4e84d23760fb2af57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Mon, 11 Mar 2024 12:52:27 +0100 Subject: [PATCH 1/4] Add zero alloc tests to TestSpanFromContext --- trace/context_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/trace/context_test.go b/trace/context_test.go index d9378e1c430..828338259f4 100644 --- a/trace/context_test.go +++ b/trace/context_test.go @@ -77,6 +77,16 @@ func TestSpanFromContext(t *testing.T) { // Ensure SpanContextFromContext is just // SpanFromContext(…).SpanContext(). assert.Equal(t, tc.expectedSpan.SpanContext(), SpanContextFromContext(tc.context)) + + // Check that SpanFromContext does not produce any heap allocation. + assert.Equal(t, 0.0, testing.AllocsPerRun(5, func() { + SpanFromContext(tc.context) + }), "SpanFromContext allocs") + + // Check that SpanContextFromContext does not produce any heap allocation. + assert.Equal(t, 0.0, testing.AllocsPerRun(5, func() { + SpanContextFromContext(tc.context) + }), "SpanFromContext allocs") }) } } From d2b832b5b00b228f5e803eee759848bae2cb6ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Mon, 11 Mar 2024 12:53:14 +0100 Subject: [PATCH 2/4] trace: SpanFromContext has no allocs --- trace/context.go | 4 ++-- trace/noop.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trace/context.go b/trace/context.go index 5074bb44557..5650a174b4a 100644 --- a/trace/context.go +++ b/trace/context.go @@ -36,12 +36,12 @@ func ContextWithRemoteSpanContext(parent context.Context, rsc SpanContext) conte // performs no operations is returned. func SpanFromContext(ctx context.Context) Span { if ctx == nil { - return noopSpan{} + return noopSpanInstance } if span, ok := ctx.Value(currentSpanKey).(Span); ok { return span } - return noopSpan{} + return noopSpanInstance } // SpanContextFromContext returns the current Span's SpanContext. diff --git a/trace/noop.go b/trace/noop.go index 583f109b064..84c775492ba 100644 --- a/trace/noop.go +++ b/trace/noop.go @@ -41,7 +41,7 @@ func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption span := SpanFromContext(ctx) if _, ok := span.(nonRecordingSpan); !ok { // span is likely already a noopSpan, but let's be sure - span = noopSpan{} + span = noopSpanInstance } return ContextWithSpan(ctx, span), span } @@ -49,7 +49,7 @@ func (t noopTracer) Start(ctx context.Context, name string, _ ...SpanStartOption // noopSpan is an implementation of Span that performs no operations. type noopSpan struct{ embedded.Span } -var _ Span = noopSpan{} +var noopSpanInstance Span = noopSpan{} // SpanContext returns an empty span context. func (noopSpan) SpanContext() SpanContext { return SpanContext{} } From 3a2dfbfc6cd576284e2956c37b43628eb6f36dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Mon, 11 Mar 2024 12:56:19 +0100 Subject: [PATCH 3/4] Fix assertion failure name --- trace/context_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trace/context_test.go b/trace/context_test.go index 828338259f4..38deb0aee5f 100644 --- a/trace/context_test.go +++ b/trace/context_test.go @@ -86,7 +86,7 @@ func TestSpanFromContext(t *testing.T) { // Check that SpanContextFromContext does not produce any heap allocation. assert.Equal(t, 0.0, testing.AllocsPerRun(5, func() { SpanContextFromContext(tc.context) - }), "SpanFromContext allocs") + }), "SpanContextFromContext allocs") }) } } From 447dd29a1e2f49c7e4d9304e14d0ffd3150d751e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Mon, 11 Mar 2024 13:00:52 +0100 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04b1d584de0..1f23df31399 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Changed + +- `SpanFromContext` and `SpanContextFromContext` in `go.opentelemetry.io/otel/trace` no longer make a heap allocation when the passed context has no span. (#5049) + ### Fixed - Clarify the documentation about equivalence guarantees for the `Set` and `Distinct` types in `go.opentelemetry.io/otel/attribute`. (#5027)