...

Source file src/go.opentelemetry.io/otel/internal/global/trace.go

Documentation: go.opentelemetry.io/otel/internal/global

     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  

View as plain text