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