mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-12-12 10:04:29 +02:00
d5292e3cd1
* Do not store TracerProvider fields in span Instead of keeping a reference to the span's Tracer, and therefore also it's TracerProvider, and the associated resource and spanLimits just keep the reference to the Tracer. Refer to the TracerProvider fields when needed instead. * Make span refer to the inst lib via the Tracer Instead of holding a field in the span, refer to the field in the parent Tracer.
150 lines
4.6 KiB
Go
150 lines
4.6 KiB
Go
// 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
|
|
instrumentationLibrary instrumentation.Library
|
|
}
|
|
|
|
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...)
|
|
|
|
// 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() {
|
|
sps, _ := tr.provider.spanProcessors.Load().(spanProcessorStates)
|
|
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{
|
|
parent: psc,
|
|
spanContext: sc,
|
|
spanKind: trace.ValidateSpanKind(config.SpanKind()),
|
|
name: name,
|
|
startTime: startTime,
|
|
attributes: newAttributesMap(tr.provider.spanLimits.AttributeCountLimit),
|
|
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}
|
|
}
|