1 // Copyright The OpenTelemetry Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package global // import "go.opentelemetry.io/otel/internal/global" 16 17 /* 18 This file contains the forwarding implementation of the TracerProvider used as 19 the default global instance. Prior to initialization of an SDK, Tracers 20 returned by the global TracerProvider will provide no-op functionality. This 21 means that all Span created prior to initialization are no-op Spans. 22 23 Once an SDK has been initialized, all provided no-op Tracers are swapped for 24 Tracers provided by the SDK defined TracerProvider. However, any Span started 25 prior to this initialization does not change its behavior. Meaning, the Span 26 remains a no-op Span. 27 28 The implementation to track and swap Tracers locks all new Tracer creation 29 until the swap is complete. This assumes that this operation is not 30 performance-critical. If that assumption is incorrect, be sure to configure an 31 SDK prior to any Tracer creation. 32 */ 33 34 import ( 35 "context" 36 "sync" 37 "sync/atomic" 38 39 "go.opentelemetry.io/otel/attribute" 40 "go.opentelemetry.io/otel/codes" 41 "go.opentelemetry.io/otel/trace" 42 "go.opentelemetry.io/otel/trace/embedded" 43 ) 44 45 // tracerProvider is a placeholder for a configured SDK TracerProvider. 46 // 47 // All TracerProvider functionality is forwarded to a delegate once 48 // configured. 49 type tracerProvider struct { 50 embedded.TracerProvider 51 52 mtx sync.Mutex 53 tracers map[il]*tracer 54 delegate trace.TracerProvider 55 } 56 57 // Compile-time guarantee that tracerProvider implements the TracerProvider 58 // interface. 59 var _ trace.TracerProvider = &tracerProvider{} 60 61 // setDelegate configures p to delegate all TracerProvider functionality to 62 // provider. 63 // 64 // All Tracers provided prior to this function call are switched out to be 65 // Tracers provided by provider. 66 // 67 // It is guaranteed by the caller that this happens only once. 68 func (p *tracerProvider) setDelegate(provider trace.TracerProvider) { 69 p.mtx.Lock() 70 defer p.mtx.Unlock() 71 72 p.delegate = provider 73 74 if len(p.tracers) == 0 { 75 return 76 } 77 78 for _, t := range p.tracers { 79 t.setDelegate(provider) 80 } 81 82 p.tracers = nil 83 } 84 85 // Tracer implements TracerProvider. 86 func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { 87 p.mtx.Lock() 88 defer p.mtx.Unlock() 89 90 if p.delegate != nil { 91 return p.delegate.Tracer(name, opts...) 92 } 93 94 // At this moment it is guaranteed that no sdk is installed, save the tracer in the tracers map. 95 96 c := trace.NewTracerConfig(opts...) 97 key := il{ 98 name: name, 99 version: c.InstrumentationVersion(), 100 } 101 102 if p.tracers == nil { 103 p.tracers = make(map[il]*tracer) 104 } 105 106 if val, ok := p.tracers[key]; ok { 107 return val 108 } 109 110 t := &tracer{name: name, opts: opts, provider: p} 111 p.tracers[key] = t 112 return t 113 } 114 115 type il struct { 116 name string 117 version string 118 } 119 120 // tracer is a placeholder for a trace.Tracer. 121 // 122 // All Tracer functionality is forwarded to a delegate once configured. 123 // Otherwise, all functionality is forwarded to a NoopTracer. 124 type tracer struct { 125 embedded.Tracer 126 127 name string 128 opts []trace.TracerOption 129 provider *tracerProvider 130 131 delegate atomic.Value 132 } 133 134 // Compile-time guarantee that tracer implements the trace.Tracer interface. 135 var _ trace.Tracer = &tracer{} 136 137 // setDelegate configures t to delegate all Tracer functionality to Tracers 138 // created by provider. 139 // 140 // All subsequent calls to the Tracer methods will be passed to the delegate. 141 // 142 // It is guaranteed by the caller that this happens only once. 143 func (t *tracer) setDelegate(provider trace.TracerProvider) { 144 t.delegate.Store(provider.Tracer(t.name, t.opts...)) 145 } 146 147 // Start implements trace.Tracer by forwarding the call to t.delegate if 148 // set, otherwise it forwards the call to a NoopTracer. 149 func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { 150 delegate := t.delegate.Load() 151 if delegate != nil { 152 return delegate.(trace.Tracer).Start(ctx, name, opts...) 153 } 154 155 s := nonRecordingSpan{sc: trace.SpanContextFromContext(ctx), tracer: t} 156 ctx = trace.ContextWithSpan(ctx, s) 157 return ctx, s 158 } 159 160 // nonRecordingSpan is a minimal implementation of a Span that wraps a 161 // SpanContext. It performs no operations other than to return the wrapped 162 // SpanContext. 163 type nonRecordingSpan struct { 164 embedded.Span 165 166 sc trace.SpanContext 167 tracer *tracer 168 } 169 170 var _ trace.Span = nonRecordingSpan{} 171 172 // SpanContext returns the wrapped SpanContext. 173 func (s nonRecordingSpan) SpanContext() trace.SpanContext { return s.sc } 174 175 // IsRecording always returns false. 176 func (nonRecordingSpan) IsRecording() bool { return false } 177 178 // SetStatus does nothing. 179 func (nonRecordingSpan) SetStatus(codes.Code, string) {} 180 181 // SetError does nothing. 182 func (nonRecordingSpan) SetError(bool) {} 183 184 // SetAttributes does nothing. 185 func (nonRecordingSpan) SetAttributes(...attribute.KeyValue) {} 186 187 // End does nothing. 188 func (nonRecordingSpan) End(...trace.SpanEndOption) {} 189 190 // RecordError does nothing. 191 func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {} 192 193 // AddEvent does nothing. 194 func (nonRecordingSpan) AddEvent(string, ...trace.EventOption) {} 195 196 // SetName does nothing. 197 func (nonRecordingSpan) SetName(string) {} 198 199 func (s nonRecordingSpan) TracerProvider() trace.TracerProvider { return s.tracer.provider } 200