123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- // Copyright The OpenTelemetry Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package 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"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/codes"
- "go.opentelemetry.io/otel/trace"
- )
- // tracerProvider is a placeholder for a configured SDK TracerProvider.
- //
- // All TracerProvider functionality is forwarded to a delegate once
- // configured.
- type tracerProvider struct {
- 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.
- key := il{
- name: name,
- version: trace.NewTracerConfig(opts...).InstrumentationVersion(),
- }
- 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
- }
- type il struct {
- name string
- version string
- }
- // 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 {
- 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...)
- }
- 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 {
- 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) {}
- // SetName does nothing.
- func (nonRecordingSpan) SetName(string) {}
- func (s nonRecordingSpan) TracerProvider() trace.TracerProvider { return s.tracer.provider }
|