| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | // 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 trace // import "go.opentelemetry.io/otel/sdk/trace" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"go.opentelemetry.io/otel/sdk/instrumentation" | 
					
						
							|  |  |  | 	"go.opentelemetry.io/otel/trace" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type tracer struct { | 
					
						
							|  |  |  | 	provider             *TracerProvider | 
					
						
							|  |  |  | 	instrumentationScope instrumentation.Scope | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _ trace.Tracer = &tracer{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Start starts a Span and returns it along with a context containing it. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The Span is created with the provided name and as a child of any existing | 
					
						
							|  |  |  | // span context found in the passed context. The created Span will be | 
					
						
							|  |  |  | // configured appropriately by any SpanOption passed. | 
					
						
							|  |  |  | func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanStartOption) (context.Context, trace.Span) { | 
					
						
							|  |  |  | 	config := trace.NewSpanStartConfig(options...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ctx == nil { | 
					
						
							|  |  |  | 		// Prevent trace.ContextWithSpan from panicking. | 
					
						
							|  |  |  | 		ctx = context.Background() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// For local spans created by this SDK, track child span count. | 
					
						
							|  |  |  | 	if p := trace.SpanFromContext(ctx); p != nil { | 
					
						
							|  |  |  | 		if sdkSpan, ok := p.(*recordingSpan); ok { | 
					
						
							|  |  |  | 			sdkSpan.addChild() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s := tr.newSpan(ctx, name, &config) | 
					
						
							|  |  |  | 	if rw, ok := s.(ReadWriteSpan); ok && s.IsRecording() { | 
					
						
							| 
									
										
										
										
											2023-05-12 14:55:18 +02:00
										 |  |  | 		sps := tr.provider.spanProcessors.Load().(spanProcessorStates) | 
					
						
							| 
									
										
										
										
											2023-05-09 19:19:48 +02:00
										 |  |  | 		for _, sp := range sps { | 
					
						
							|  |  |  | 			sp.sp.OnStart(ctx, rw) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if rtt, ok := s.(runtimeTracer); ok { | 
					
						
							|  |  |  | 		ctx = rtt.runtimeTrace(ctx) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return trace.ContextWithSpan(ctx, s), s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type runtimeTracer interface { | 
					
						
							|  |  |  | 	// runtimeTrace starts a "runtime/trace".Task for the span and | 
					
						
							|  |  |  | 	// returns a context containing the task. | 
					
						
							|  |  |  | 	runtimeTrace(ctx context.Context) context.Context | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newSpan returns a new configured span. | 
					
						
							|  |  |  | func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanConfig) trace.Span { | 
					
						
							|  |  |  | 	// If told explicitly to make this a new root use a zero value SpanContext | 
					
						
							|  |  |  | 	// as a parent which contains an invalid trace ID and is not remote. | 
					
						
							|  |  |  | 	var psc trace.SpanContext | 
					
						
							|  |  |  | 	if config.NewRoot() { | 
					
						
							|  |  |  | 		ctx = trace.ContextWithSpanContext(ctx, psc) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		psc = trace.SpanContextFromContext(ctx) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If there is a valid parent trace ID, use it to ensure the continuity of | 
					
						
							|  |  |  | 	// the trace. Always generate a new span ID so other components can rely | 
					
						
							|  |  |  | 	// on a unique span ID, even if the Span is non-recording. | 
					
						
							|  |  |  | 	var tid trace.TraceID | 
					
						
							|  |  |  | 	var sid trace.SpanID | 
					
						
							|  |  |  | 	if !psc.TraceID().IsValid() { | 
					
						
							|  |  |  | 		tid, sid = tr.provider.idGenerator.NewIDs(ctx) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		tid = psc.TraceID() | 
					
						
							|  |  |  | 		sid = tr.provider.idGenerator.NewSpanID(ctx, tid) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	samplingResult := tr.provider.sampler.ShouldSample(SamplingParameters{ | 
					
						
							|  |  |  | 		ParentContext: ctx, | 
					
						
							|  |  |  | 		TraceID:       tid, | 
					
						
							|  |  |  | 		Name:          name, | 
					
						
							|  |  |  | 		Kind:          config.SpanKind(), | 
					
						
							|  |  |  | 		Attributes:    config.Attributes(), | 
					
						
							|  |  |  | 		Links:         config.Links(), | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	scc := trace.SpanContextConfig{ | 
					
						
							|  |  |  | 		TraceID:    tid, | 
					
						
							|  |  |  | 		SpanID:     sid, | 
					
						
							|  |  |  | 		TraceState: samplingResult.Tracestate, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if isSampled(samplingResult) { | 
					
						
							|  |  |  | 		scc.TraceFlags = psc.TraceFlags() | trace.FlagsSampled | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		scc.TraceFlags = psc.TraceFlags() &^ trace.FlagsSampled | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sc := trace.NewSpanContext(scc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !isRecording(samplingResult) { | 
					
						
							|  |  |  | 		return tr.newNonRecordingSpan(sc) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return tr.newRecordingSpan(psc, sc, name, samplingResult, config) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newRecordingSpan returns a new configured recordingSpan. | 
					
						
							|  |  |  | func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr SamplingResult, config *trace.SpanConfig) *recordingSpan { | 
					
						
							|  |  |  | 	startTime := config.Timestamp() | 
					
						
							|  |  |  | 	if startTime.IsZero() { | 
					
						
							|  |  |  | 		startTime = time.Now() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s := &recordingSpan{ | 
					
						
							|  |  |  | 		// Do not pre-allocate the attributes slice here! Doing so will | 
					
						
							|  |  |  | 		// allocate memory that is likely never going to be used, or if used, | 
					
						
							|  |  |  | 		// will be over-sized. The default Go compiler has been tested to | 
					
						
							|  |  |  | 		// dynamically allocate needed space very well. Benchmarking has shown | 
					
						
							|  |  |  | 		// it to be more performant than what we can predetermine here, | 
					
						
							|  |  |  | 		// especially for the common use case of few to no added | 
					
						
							|  |  |  | 		// attributes. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		parent:      psc, | 
					
						
							|  |  |  | 		spanContext: sc, | 
					
						
							|  |  |  | 		spanKind:    trace.ValidateSpanKind(config.SpanKind()), | 
					
						
							|  |  |  | 		name:        name, | 
					
						
							|  |  |  | 		startTime:   startTime, | 
					
						
							|  |  |  | 		events:      newEvictedQueue(tr.provider.spanLimits.EventCountLimit), | 
					
						
							|  |  |  | 		links:       newEvictedQueue(tr.provider.spanLimits.LinkCountLimit), | 
					
						
							|  |  |  | 		tracer:      tr, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, l := range config.Links() { | 
					
						
							|  |  |  | 		s.addLink(l) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.SetAttributes(sr.Attributes...) | 
					
						
							|  |  |  | 	s.SetAttributes(config.Attributes()...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newNonRecordingSpan returns a new configured nonRecordingSpan. | 
					
						
							|  |  |  | func (tr *tracer) newNonRecordingSpan(sc trace.SpanContext) nonRecordingSpan { | 
					
						
							|  |  |  | 	return nonRecordingSpan{tracer: tr, sc: sc} | 
					
						
							|  |  |  | } |