| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // Copyright The OpenTelemetry Authors | 
					
						
							| 
									
										
										
										
											2024-04-11 11:46:18 +02:00
										 |  |  | // SPDX-License-Identifier: Apache-2.0 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | package global // import "go.opentelemetry.io/otel/internal/global" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | This file contains the forwarding implementation of the TracerProvider used as | 
					
						
							|  |  |  | the default global instance. Prior to initialization of an SDK, Tracers | 
					
						
							|  |  |  | returned by the global TracerProvider will provide no-op functionality. This | 
					
						
							|  |  |  | means that all Span created prior to initialization are no-op Spans. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Once an SDK has been initialized, all provided no-op Tracers are swapped for | 
					
						
							|  |  |  | Tracers provided by the SDK defined TracerProvider. However, any Span started | 
					
						
							|  |  |  | prior to this initialization does not change its behavior. Meaning, the Span | 
					
						
							|  |  |  | remains a no-op Span. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The implementation to track and swap Tracers locks all new Tracer creation | 
					
						
							|  |  |  | until the swap is complete. This assumes that this operation is not | 
					
						
							|  |  |  | performance-critical. If that assumption is incorrect, be sure to configure an | 
					
						
							|  |  |  | SDK prior to any Tracer creation. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 12:14:37 +01:00
										 |  |  | 	"go.opentelemetry.io/auto/sdk" | 
					
						
							| 
									
										
										
										
											2025-09-04 15:29:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	"go.opentelemetry.io/otel/attribute" | 
					
						
							|  |  |  | 	"go.opentelemetry.io/otel/codes" | 
					
						
							|  |  |  | 	"go.opentelemetry.io/otel/trace" | 
					
						
							| 
									
										
										
										
											2023-11-13 11:08:02 +01:00
										 |  |  | 	"go.opentelemetry.io/otel/trace/embedded" | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // tracerProvider is a placeholder for a configured SDK TracerProvider. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // All TracerProvider functionality is forwarded to a delegate once | 
					
						
							|  |  |  | // configured. | 
					
						
							|  |  |  | type tracerProvider struct { | 
					
						
							| 
									
										
										
										
											2023-11-13 11:08:02 +01:00
										 |  |  | 	embedded.TracerProvider | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	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 (p *tracerProvider) setDelegate(provider trace.TracerProvider) { | 
					
						
							|  |  |  | 	p.mtx.Lock() | 
					
						
							|  |  |  | 	defer p.mtx.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p.delegate = provider | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(p.tracers) == 0 { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, t := range p.tracers { | 
					
						
							|  |  |  | 		t.setDelegate(provider) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p.tracers = nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Tracer implements TracerProvider. | 
					
						
							|  |  |  | func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { | 
					
						
							|  |  |  | 	p.mtx.Lock() | 
					
						
							|  |  |  | 	defer p.mtx.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if p.delegate != nil { | 
					
						
							|  |  |  | 		return p.delegate.Tracer(name, opts...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// At this moment it is guaranteed that no sdk is installed, save the tracer in the tracers map. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	c := trace.NewTracerConfig(opts...) | 
					
						
							|  |  |  | 	key := il{ | 
					
						
							|  |  |  | 		name:    name, | 
					
						
							|  |  |  | 		version: c.InstrumentationVersion(), | 
					
						
							| 
									
										
										
										
											2024-08-26 18:05:54 +02:00
										 |  |  | 		schema:  c.SchemaURL(), | 
					
						
							| 
									
										
										
										
											2025-02-06 12:14:37 +01:00
										 |  |  | 		attrs:   c.InstrumentationAttributes(), | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if p.tracers == nil { | 
					
						
							|  |  |  | 		p.tracers = make(map[il]*tracer) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if val, ok := p.tracers[key]; ok { | 
					
						
							|  |  |  | 		return val | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t := &tracer{name: name, opts: opts, provider: p} | 
					
						
							|  |  |  | 	p.tracers[key] = t | 
					
						
							|  |  |  | 	return t | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 12:14:37 +01:00
										 |  |  | type il struct { | 
					
						
							|  |  |  | 	name    string | 
					
						
							|  |  |  | 	version string | 
					
						
							|  |  |  | 	schema  string | 
					
						
							|  |  |  | 	attrs   attribute.Set | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2023-11-13 11:08:02 +01:00
										 |  |  | 	embedded.Tracer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	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 (t *tracer) setDelegate(provider trace.TracerProvider) { | 
					
						
							|  |  |  | 	t.delegate.Store(provider.Tracer(t.name, t.opts...)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Start implements trace.Tracer by forwarding the call to t.delegate if | 
					
						
							|  |  |  | // set, otherwise it forwards the call to a NoopTracer. | 
					
						
							|  |  |  | func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { | 
					
						
							|  |  |  | 	delegate := t.delegate.Load() | 
					
						
							|  |  |  | 	if delegate != nil { | 
					
						
							|  |  |  | 		return delegate.(trace.Tracer).Start(ctx, name, opts...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 12:14:37 +01:00
										 |  |  | 	return t.newSpan(ctx, autoInstEnabled, name, opts) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-22 16:27:55 +02:00
										 |  |  | // 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:noinline | 
					
						
							|  |  |  | func (t *tracer) newSpan( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	autoSpan *bool, | 
					
						
							|  |  |  | 	name string, | 
					
						
							|  |  |  | 	opts []trace.SpanStartOption, | 
					
						
							|  |  |  | ) (context.Context, trace.Span) { | 
					
						
							| 
									
										
										
										
											2025-02-06 12:14:37 +01:00
										 |  |  | 	// 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 *autoSpan { | 
					
						
							|  |  |  | 		tracer := sdk.TracerProvider().Tracer(t.name, t.opts...) | 
					
						
							|  |  |  | 		return tracer.Start(ctx, name, opts...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	s := nonRecordingSpan{sc: trace.SpanContextFromContext(ctx), tracer: t} | 
					
						
							|  |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2023-11-13 11:08:02 +01:00
										 |  |  | 	embedded.Span | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 	sc     trace.SpanContext | 
					
						
							|  |  |  | 	tracer *tracer | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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.SpanEndOption) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RecordError does nothing. | 
					
						
							|  |  |  | func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AddEvent does nothing. | 
					
						
							|  |  |  | func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-11 11:46:18 +02:00
										 |  |  | // AddLink does nothing. | 
					
						
							|  |  |  | func (nonRecordingSpan) AddLink(trace.Link) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // SetName does nothing. | 
					
						
							|  |  |  | func (nonRecordingSpan) SetName(string) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s nonRecordingSpan) TracerProvider() trace.TracerProvider { return s.tracer.provider } |