...

Source file src/go.opentelemetry.io/otel/sdk/trace/tracer.go

Documentation: go.opentelemetry.io/otel/sdk/trace

     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 trace // import "go.opentelemetry.io/otel/sdk/trace"
    16  
    17  import (
    18  	"context"
    19  	"time"
    20  
    21  	"go.opentelemetry.io/otel/sdk/instrumentation"
    22  	"go.opentelemetry.io/otel/trace"
    23  	"go.opentelemetry.io/otel/trace/embedded"
    24  )
    25  
    26  type tracer struct {
    27  	embedded.Tracer
    28  
    29  	provider             *TracerProvider
    30  	instrumentationScope instrumentation.Scope
    31  }
    32  
    33  var _ trace.Tracer = &tracer{}
    34  
    35  // Start starts a Span and returns it along with a context containing it.
    36  //
    37  // The Span is created with the provided name and as a child of any existing
    38  // span context found in the passed context. The created Span will be
    39  // configured appropriately by any SpanOption passed.
    40  func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanStartOption) (context.Context, trace.Span) {
    41  	config := trace.NewSpanStartConfig(options...)
    42  
    43  	if ctx == nil {
    44  		// Prevent trace.ContextWithSpan from panicking.
    45  		ctx = context.Background()
    46  	}
    47  
    48  	// For local spans created by this SDK, track child span count.
    49  	if p := trace.SpanFromContext(ctx); p != nil {
    50  		if sdkSpan, ok := p.(*recordingSpan); ok {
    51  			sdkSpan.addChild()
    52  		}
    53  	}
    54  
    55  	s := tr.newSpan(ctx, name, &config)
    56  	if rw, ok := s.(ReadWriteSpan); ok && s.IsRecording() {
    57  		sps := tr.provider.getSpanProcessors()
    58  		for _, sp := range sps {
    59  			sp.sp.OnStart(ctx, rw)
    60  		}
    61  	}
    62  	if rtt, ok := s.(runtimeTracer); ok {
    63  		ctx = rtt.runtimeTrace(ctx)
    64  	}
    65  
    66  	return trace.ContextWithSpan(ctx, s), s
    67  }
    68  
    69  type runtimeTracer interface {
    70  	// runtimeTrace starts a "runtime/trace".Task for the span and
    71  	// returns a context containing the task.
    72  	runtimeTrace(ctx context.Context) context.Context
    73  }
    74  
    75  // newSpan returns a new configured span.
    76  func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanConfig) trace.Span {
    77  	// If told explicitly to make this a new root use a zero value SpanContext
    78  	// as a parent which contains an invalid trace ID and is not remote.
    79  	var psc trace.SpanContext
    80  	if config.NewRoot() {
    81  		ctx = trace.ContextWithSpanContext(ctx, psc)
    82  	} else {
    83  		psc = trace.SpanContextFromContext(ctx)
    84  	}
    85  
    86  	// If there is a valid parent trace ID, use it to ensure the continuity of
    87  	// the trace. Always generate a new span ID so other components can rely
    88  	// on a unique span ID, even if the Span is non-recording.
    89  	var tid trace.TraceID
    90  	var sid trace.SpanID
    91  	if !psc.TraceID().IsValid() {
    92  		tid, sid = tr.provider.idGenerator.NewIDs(ctx)
    93  	} else {
    94  		tid = psc.TraceID()
    95  		sid = tr.provider.idGenerator.NewSpanID(ctx, tid)
    96  	}
    97  
    98  	samplingResult := tr.provider.sampler.ShouldSample(SamplingParameters{
    99  		ParentContext: ctx,
   100  		TraceID:       tid,
   101  		Name:          name,
   102  		Kind:          config.SpanKind(),
   103  		Attributes:    config.Attributes(),
   104  		Links:         config.Links(),
   105  	})
   106  
   107  	scc := trace.SpanContextConfig{
   108  		TraceID:    tid,
   109  		SpanID:     sid,
   110  		TraceState: samplingResult.Tracestate,
   111  	}
   112  	if isSampled(samplingResult) {
   113  		scc.TraceFlags = psc.TraceFlags() | trace.FlagsSampled
   114  	} else {
   115  		scc.TraceFlags = psc.TraceFlags() &^ trace.FlagsSampled
   116  	}
   117  	sc := trace.NewSpanContext(scc)
   118  
   119  	if !isRecording(samplingResult) {
   120  		return tr.newNonRecordingSpan(sc)
   121  	}
   122  	return tr.newRecordingSpan(psc, sc, name, samplingResult, config)
   123  }
   124  
   125  // newRecordingSpan returns a new configured recordingSpan.
   126  func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr SamplingResult, config *trace.SpanConfig) *recordingSpan {
   127  	startTime := config.Timestamp()
   128  	if startTime.IsZero() {
   129  		startTime = time.Now()
   130  	}
   131  
   132  	s := &recordingSpan{
   133  		// Do not pre-allocate the attributes slice here! Doing so will
   134  		// allocate memory that is likely never going to be used, or if used,
   135  		// will be over-sized. The default Go compiler has been tested to
   136  		// dynamically allocate needed space very well. Benchmarking has shown
   137  		// it to be more performant than what we can predetermine here,
   138  		// especially for the common use case of few to no added
   139  		// attributes.
   140  
   141  		parent:      psc,
   142  		spanContext: sc,
   143  		spanKind:    trace.ValidateSpanKind(config.SpanKind()),
   144  		name:        name,
   145  		startTime:   startTime,
   146  		events:      newEvictedQueue(tr.provider.spanLimits.EventCountLimit),
   147  		links:       newEvictedQueue(tr.provider.spanLimits.LinkCountLimit),
   148  		tracer:      tr,
   149  	}
   150  
   151  	for _, l := range config.Links() {
   152  		s.addLink(l)
   153  	}
   154  
   155  	s.SetAttributes(sr.Attributes...)
   156  	s.SetAttributes(config.Attributes()...)
   157  
   158  	return s
   159  }
   160  
   161  // newNonRecordingSpan returns a new configured nonRecordingSpan.
   162  func (tr *tracer) newNonRecordingSpan(sc trace.SpanContext) nonRecordingSpan {
   163  	return nonRecordingSpan{tracer: tr, sc: sc}
   164  }
   165  

View as plain text