// Copyright The OpenTelemetry Authors// SPDX-License-Identifier: Apache-2.0package global // import "go.opentelemetry.io/otel/internal/global"/*This file contains the forwarding implementation of the TracerProvider used asthe default global instance. Prior to initialization of an SDK, Tracersreturned by the global TracerProvider will provide no-op functionality. Thismeans that all Span created prior to initialization are no-op Spans.Once an SDK has been initialized, all provided no-op Tracers are swapped forTracers provided by the SDK defined TracerProvider. However, any Span startedprior to this initialization does not change its behavior. Meaning, the Spanremains a no-op Span.The implementation to track and swap Tracers locks all new Tracer creationuntil the swap is complete. This assumes that this operation is notperformance-critical. If that assumption is incorrect, be sure to configure anSDK prior to any Tracer creation.*/import ()// tracerProvider is a placeholder for a configured SDK TracerProvider.//// All TracerProvider functionality is forwarded to a delegate once// configured.type tracerProvider struct {embedded.TracerProvider mtx sync.Mutex tracers map[il]*tracer delegate trace.TracerProvider}// Compile-time guarantee that tracerProvider implements the TracerProvider// interface.var _ trace.TracerProvider = &tracerProvider{}// setDelegate configures p to delegate all TracerProvider functionality to// provider.//// All Tracers provided prior to this function call are switched out to be// Tracers provided by provider.//// It is guaranteed by the caller that this happens only once.func ( *tracerProvider) ( trace.TracerProvider) { .mtx.Lock()defer .mtx.Unlock() .delegate = iflen(.tracers) == 0 {return }for , := range .tracers { .setDelegate() } .tracers = nil}// Tracer implements TracerProvider.func ( *tracerProvider) ( string, ...trace.TracerOption) trace.Tracer { .mtx.Lock()defer .mtx.Unlock()if .delegate != nil {return .delegate.Tracer(, ...) }// At this moment it is guaranteed that no sdk is installed, save the tracer in the tracers map. := trace.NewTracerConfig(...) := il{name: ,version: .InstrumentationVersion(),schema: .SchemaURL(),attrs: .InstrumentationAttributes(), }if .tracers == nil { .tracers = make(map[il]*tracer) }if , := .tracers[]; {return } := &tracer{name: , opts: , provider: } .tracers[] = return}type il struct { name string version string schema string attrs attribute.Set}// tracer is a placeholder for a trace.Tracer.//// All Tracer functionality is forwarded to a delegate once configured.// Otherwise, all functionality is forwarded to a NoopTracer.type tracer struct {embedded.Tracer name string opts []trace.TracerOption provider *tracerProvider delegate atomic.Value}// Compile-time guarantee that tracer implements the trace.Tracer interface.var _ trace.Tracer = &tracer{}// setDelegate configures t to delegate all Tracer functionality to Tracers// created by provider.//// All subsequent calls to the Tracer methods will be passed to the delegate.//// It is guaranteed by the caller that this happens only once.func ( *tracer) ( trace.TracerProvider) { .delegate.Store(.Tracer(.name, .opts...))}// Start implements trace.Tracer by forwarding the call to t.delegate if// set, otherwise it forwards the call to a NoopTracer.func ( *tracer) ( context.Context, string, ...trace.SpanStartOption) (context.Context, trace.Span) { := .delegate.Load()if != nil {return .(trace.Tracer).Start(, , ...) }return .newSpan(, autoInstEnabled, , )}// autoInstEnabled determines if the auto-instrumentation SDK span is returned// from the tracer when not backed by a delegate and auto-instrumentation has// attached to this process.//// The auto-instrumentation is expected to overwrite this value to true when it// attaches. By default, this will point to false and mean a tracer will return// a nonRecordingSpan by default.var autoInstEnabled = new(bool)// newSpan is called by tracer.Start so auto-instrumentation can attach an eBPF// uprobe to this code.//// "noinline" pragma prevents the method from ever being inlined.////go:noinlinefunc ( *tracer) (context.Context, *bool,string, []trace.SpanStartOption,) (context.Context, trace.Span) {// autoInstEnabled is passed to newSpan via the autoSpan parameter. This is // so the auto-instrumentation can define a uprobe for (*t).newSpan and be // provided with the address of the bool autoInstEnabled points to. It // needs to be a parameter so that pointer can be reliably determined, it // should not be read from the global.if * { := sdk.TracerProvider().Tracer(.name, .opts...)return .Start(, , ...) } := nonRecordingSpan{sc: trace.SpanContextFromContext(), tracer: } = trace.ContextWithSpan(, )return , }// 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 {embedded.Span sc trace.SpanContext tracer *tracer}var _ trace.Span = nonRecordingSpan{}// SpanContext returns the wrapped SpanContext.func ( nonRecordingSpan) () trace.SpanContext { return .sc }// IsRecording always returns false.func (nonRecordingSpan) () bool { returnfalse }// SetStatus does nothing.func (nonRecordingSpan) (codes.Code, string) {}// SetError does nothing.func (nonRecordingSpan) (bool) {}// SetAttributes does nothing.func (nonRecordingSpan) (...attribute.KeyValue) {}// End does nothing.func (nonRecordingSpan) (...trace.SpanEndOption) {}// RecordError does nothing.func (nonRecordingSpan) (error, ...trace.EventOption) {}// AddEvent does nothing.func (nonRecordingSpan) (string, ...trace.EventOption) {}// AddLink does nothing.func (nonRecordingSpan) (trace.Link) {}// SetName does nothing.func (nonRecordingSpan) (string) {}func ( nonRecordingSpan) () trace.TracerProvider { return .tracer.provider }
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.