Skip to content

Commit

Permalink
Implement global default non-recording span (#1901)
Browse files Browse the repository at this point in the history
* Remove the Tracer method from the Span API

* Update CHANGELOG with changes

* Update CHANGELOG.md

* Fix misspell

* Address feedback

* Implement global default non-recording span

* Add changes to CHANGELOG

* Update PR number in changelog
  • Loading branch information
MrAlias committed May 12, 2021
1 parent b6d5442 commit 63e0ecf
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `ExportSpans` method of the`SpanExporter` interface type was updated to accept `ReadOnlySpan`s instead of the removed `SpanSnapshot`.
This brings the export interface into compliance with the specification in that it now accepts an explicitly immutable type instead of just an implied one. (#1873)
- Unembed `SpanContext` in `Link`. (#1877)
- Spans created by the global `Tracer` obtained from `go.opentelemetry.io/otel`, prior to a functioning `TracerProvider` being set, now propagate the span context from their parent if one exists. (#1901)

### Deprecated

Expand Down
44 changes: 42 additions & 2 deletions internal/global/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ import (
"sync"
"sync/atomic"

"go.opentelemetry.io/otel/internal/trace/noop"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
)

Expand Down Expand Up @@ -143,5 +144,44 @@ func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanOptio
if delegate != nil {
return delegate.(trace.Tracer).Start(ctx, name, opts...)
}
return noop.Tracer.Start(ctx, name, opts...)

s := nonRecordingSpan{sc: trace.SpanContextFromContext(ctx)}
ctx = trace.ContextWithSpan(ctx, s)
return ctx, s
}

// nonRecordingSpan is a minimal implementation of a Span that wraps a
// SpanContext. It performs no operations other than to return the wrapped
// SpanContext.
type nonRecordingSpan struct {
sc trace.SpanContext
}

var _ trace.Span = nonRecordingSpan{}

// SpanContext returns the wrapped SpanContext.
func (s nonRecordingSpan) SpanContext() trace.SpanContext { return s.sc }

// IsRecording always returns false.
func (nonRecordingSpan) IsRecording() bool { return false }

// SetStatus does nothing.
func (nonRecordingSpan) SetStatus(codes.Code, string) {}

// SetError does nothing.
func (nonRecordingSpan) SetError(bool) {}

// SetAttributes does nothing.
func (nonRecordingSpan) SetAttributes(...attribute.KeyValue) {}

// End does nothing.
func (nonRecordingSpan) End(...trace.SpanOption) {}

// RecordError does nothing.
func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}

// AddEvent does nothing.
func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {}

// SetName does nothing.
func (nonRecordingSpan) SetName(string) {}
16 changes: 16 additions & 0 deletions internal/global/trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,19 @@ func TestTraceProviderDelegatesSameInstance(t *testing.T) {

assert.NotSame(t, tracer, gtp.Tracer("abc", trace.WithInstrumentationVersion("xyz")))
}

func TestSpanContextPropagatedWithNonRecordingSpan(t *testing.T) {
global.ResetForTest()

sc := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: [16]byte{0x01},
SpanID: [8]byte{0x01},
TraceFlags: trace.FlagsSampled,
Remote: true,
})
ctx := trace.ContextWithSpanContext(context.Background(), sc)
_, span := otel.Tracer("test").Start(ctx, "test")

assert.Equal(t, sc, span.SpanContext())
assert.False(t, span.IsRecording())
}

0 comments on commit 63e0ecf

Please sign in to comment.