forked from open-telemetry/opentelemetry-go-instrumentation
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move the tracer type and related functionality to its own file to help discoverability. Test the tracer type including its concurrent safety (part of open-telemetry#1297).
- Loading branch information
Showing
3 changed files
with
175 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package sdk | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"go.opentelemetry.io/otel/trace" | ||
"go.opentelemetry.io/otel/trace/noop" | ||
|
||
"go.opentelemetry.io/auto/sdk/internal/telemetry" | ||
) | ||
|
||
type tracer struct { | ||
noop.Tracer | ||
|
||
name, schemaURL, version string | ||
} | ||
|
||
var _ trace.Tracer = tracer{} | ||
|
||
func (t tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { | ||
var psc trace.SpanContext | ||
span := &span{sampled: true} | ||
|
||
// Ask eBPF for sampling decision and span context info. | ||
t.start(ctx, span, &psc, &span.sampled, &span.spanContext) | ||
|
||
ctx = trace.ContextWithSpan(ctx, span) | ||
|
||
if span.sampled { | ||
// Only build traces if sampled. | ||
cfg := trace.NewSpanStartConfig(opts...) | ||
span.traces, span.span = t.traces(ctx, name, cfg, span.spanContext, psc) | ||
} | ||
|
||
return ctx, span | ||
} | ||
|
||
// Expected to be implemented in eBPF. | ||
// | ||
//go:noinline | ||
func (t *tracer) start( | ||
ctx context.Context, | ||
spanPtr *span, | ||
psc *trace.SpanContext, | ||
sampled *bool, | ||
sc *trace.SpanContext, | ||
) { | ||
start(ctx, spanPtr, psc, sampled, sc) | ||
} | ||
|
||
// start is used for testing. | ||
var start = func(context.Context, *span, *trace.SpanContext, *bool, *trace.SpanContext) {} | ||
|
||
func (t tracer) traces(ctx context.Context, name string, cfg trace.SpanConfig, sc, psc trace.SpanContext) (*telemetry.Traces, *telemetry.Span) { | ||
span := &telemetry.Span{ | ||
TraceID: telemetry.TraceID(sc.TraceID()), | ||
SpanID: telemetry.SpanID(sc.SpanID()), | ||
Flags: uint32(sc.TraceFlags()), | ||
TraceState: sc.TraceState().String(), | ||
ParentSpanID: telemetry.SpanID(psc.SpanID()), | ||
Name: name, | ||
Kind: spanKind(cfg.SpanKind()), | ||
Attrs: convAttrs(cfg.Attributes()), | ||
Links: convLinks(cfg.Links()), | ||
} | ||
|
||
if t := cfg.Timestamp(); !t.IsZero() { | ||
span.StartTime = cfg.Timestamp() | ||
} else { | ||
span.StartTime = time.Now() | ||
} | ||
|
||
return &telemetry.Traces{ | ||
ResourceSpans: []*telemetry.ResourceSpans{ | ||
{ | ||
ScopeSpans: []*telemetry.ScopeSpans{ | ||
{ | ||
Scope: &telemetry.Scope{ | ||
Name: t.name, | ||
Version: t.version, | ||
}, | ||
Spans: []*telemetry.Span{span}, | ||
SchemaURL: t.schemaURL, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, span | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package sdk | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
"sync" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"go.opentelemetry.io/otel/trace" | ||
) | ||
|
||
const tName = "tracer.name" | ||
|
||
func TestTracerStartPropagatesOrigCtx(t *testing.T) { | ||
t.Parallel() | ||
|
||
type ctxKey struct{} | ||
var key ctxKey | ||
val := "value" | ||
|
||
ctx := context.WithValue(context.Background(), key, val) | ||
ctx, _ = TracerProvider().Tracer(tName).Start(ctx, "span.name") | ||
|
||
assert.Equal(t, val, ctx.Value(key)) | ||
} | ||
|
||
func TestTracerStartReturnsNonNilSpan(t *testing.T) { | ||
t.Parallel() | ||
|
||
tr := TracerProvider().Tracer(tName) | ||
_, s := tr.Start(context.Background(), "span.name") | ||
assert.NotNil(t, s) | ||
} | ||
|
||
func TestTracerStartAddsSpanToCtx(t *testing.T) { | ||
t.Parallel() | ||
|
||
tr := TracerProvider().Tracer(tName) | ||
ctx, s := tr.Start(context.Background(), "span.name") | ||
|
||
assert.Same(t, s, trace.SpanFromContext(ctx)) | ||
} | ||
|
||
func TestTracerConcurrentSafe(t *testing.T) { | ||
t.Parallel() | ||
|
||
const goroutines = 10 | ||
|
||
ctx := context.Background() | ||
run := func(tracer trace.Tracer) <-chan struct{} { | ||
done := make(chan struct{}) | ||
|
||
go func(tr trace.Tracer) { | ||
defer close(done) | ||
|
||
var wg sync.WaitGroup | ||
for i := 0; i < goroutines; i++ { | ||
wg.Add(1) | ||
go func(name string) { | ||
defer wg.Done() | ||
_, _ = tr.Start(ctx, name) | ||
}("span" + strconv.Itoa(i)) | ||
} | ||
|
||
wg.Wait() | ||
}(tracer) | ||
|
||
return done | ||
} | ||
|
||
assert.NotPanics(t, func() { | ||
tp := TracerProvider() | ||
done0, done1 := run(tp.Tracer("t0")), run(tp.Tracer("t1")) | ||
|
||
<-done0 | ||
<-done1 | ||
}) | ||
} |