You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-09-16 09:26:25 +02:00
Track context containing span in recordingSpan
(#7354)
Avoid the allocation of re-embedding the span in a context on end by keeping the one created on start in the span. ### Benchmarks ``` goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/sdk/trace cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz │ main.out │ trace-recording-span-ctx.out │ │ sec/op │ sec/op vs base │ SpanEnd/ObservabilityEnabled-8 248.2n ± 5% 186.2n ± 4% -24.94% (p=0.000 n=20) TraceStart/ObservabilityEnabled-8 935.8n ± 2% 995.9n ± 4% +6.43% (p=0.000 n=20) geomean 481.9n 430.7n -10.62% │ main.out │ trace-recording-span-ctx.out │ │ B/op │ B/op vs base │ SpanEnd/ObservabilityEnabled-8 64.00 ± 0% 16.00 ± 0% -75.00% (p=0.000 n=20) TraceStart/ObservabilityEnabled-8 608.0 ± 0% 608.0 ± 0% ~ (p=1.000 n=20) ¹ geomean 197.3 98.63 -50.00% ¹ all samples are equal │ main.out │ trace-recording-span-ctx.out │ │ allocs/op │ allocs/op vs base │ SpanEnd/ObservabilityEnabled-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=20) TraceStart/ObservabilityEnabled-8 5.000 ± 0% 5.000 ± 0% ~ (p=1.000 n=20) ¹ geomean 3.162 2.236 -29.29% ¹ all samples are equal ```
This commit is contained in:
@@ -151,6 +151,12 @@ type recordingSpan struct {
|
||||
|
||||
// tracer is the SDK tracer that created this span.
|
||||
tracer *tracer
|
||||
|
||||
// origCtx is the context used when starting this span that has the
|
||||
// recordingSpan instance set as the active span. If not nil, it is used
|
||||
// when ending the span to ensure any metrics are recorded with a context
|
||||
// containing this span without requiring an additional allocation.
|
||||
origCtx context.Context
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -158,6 +164,10 @@ var (
|
||||
_ runtimeTracer = (*recordingSpan)(nil)
|
||||
)
|
||||
|
||||
func (s *recordingSpan) setOrigCtx(ctx context.Context) {
|
||||
s.origCtx = ctx
|
||||
}
|
||||
|
||||
// SpanContext returns the SpanContext of this span.
|
||||
func (s *recordingSpan) SpanContext() trace.SpanContext {
|
||||
if s == nil {
|
||||
@@ -497,13 +507,17 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
|
||||
s.mu.Unlock()
|
||||
|
||||
if s.tracer.observabilityEnabled {
|
||||
defer func() {
|
||||
// Add the span to the context to ensure the metric is recorded
|
||||
// with the correct span context.
|
||||
ctx := trace.ContextWithSpan(context.Background(), s)
|
||||
ctx := s.origCtx
|
||||
if ctx == nil {
|
||||
// This should not happen as the origCtx should be set, but
|
||||
// ensure trace information is propagated in the case of an
|
||||
// error.
|
||||
ctx = trace.ContextWithSpan(context.Background(), s)
|
||||
}
|
||||
defer func(ctx context.Context) {
|
||||
set := spanLiveSet(s.spanContext.IsSampled())
|
||||
s.tracer.spanLiveMetric.AddSet(ctx, -1, set)
|
||||
}()
|
||||
}(ctx)
|
||||
}
|
||||
|
||||
sps := s.tracer.provider.getSpanProcessors()
|
||||
|
@@ -2780,15 +2780,8 @@ func TestObservabilityContextPropagation(t *testing.T) {
|
||||
isValid := s.SpanContext().IsValid()
|
||||
assert.True(t, isValid, "Context should have a valid span")
|
||||
|
||||
if s.IsRecording() {
|
||||
// Check if the context value is propagated correctly for Span
|
||||
// starts. The Span end operation does not receive any user
|
||||
// context so do not check this if the span is not recording
|
||||
// (i.e. end operation).
|
||||
|
||||
got := ctx.Value(ctxKey)
|
||||
assert.Equal(t, want, got, "Context value not propagated")
|
||||
}
|
||||
got := ctx.Value(ctxKey)
|
||||
assert.Equal(t, want, got, "Context value not propagated")
|
||||
}
|
||||
n <- count
|
||||
}()
|
||||
|
@@ -54,6 +54,14 @@ func (tr *tracer) Start(
|
||||
s := tr.newSpan(ctx, name, &config)
|
||||
newCtx := trace.ContextWithSpan(ctx, s)
|
||||
if tr.observabilityEnabled {
|
||||
if o, ok := s.(interface{ setOrigCtx(context.Context) }); ok {
|
||||
// If this is a recording span, store the original context.
|
||||
// This allows later retrieval of baggage and other information
|
||||
// that may have been stored in the context at span start time and
|
||||
// to avoid the allocation of repeatedly calling
|
||||
// trace.ContextWithSpan.
|
||||
o.setOrigCtx(newCtx)
|
||||
}
|
||||
psc := trace.SpanContextFromContext(ctx)
|
||||
set := spanStartedSet(psc, s)
|
||||
tr.spanStartedMetric.AddSet(newCtx, 1, set)
|
||||
|
Reference in New Issue
Block a user