Skip to content

Commit 1e18294

Browse files
committed
add tracerprovider instrumentation
1 parent f508b24 commit 1e18294

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

sdk/trace/provider.go

+56
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import (
1010
"sync/atomic"
1111

1212
"go.opentelemetry.io/otel"
13+
"go.opentelemetry.io/otel/attribute"
1314
"go.opentelemetry.io/otel/internal/global"
15+
"go.opentelemetry.io/otel/metric"
16+
metricnoop "go.opentelemetry.io/otel/metric/noop"
1417
"go.opentelemetry.io/otel/sdk/instrumentation"
18+
"go.opentelemetry.io/otel/sdk/internal/x"
1519
"go.opentelemetry.io/otel/sdk/resource"
1620
"go.opentelemetry.io/otel/trace"
1721
"go.opentelemetry.io/otel/trace/embedded"
@@ -79,6 +83,12 @@ type TracerProvider struct {
7983
idGenerator IDGenerator
8084
spanLimits SpanLimits
8185
resource *resource.Resource
86+
87+
spanCreatedCount metric.Int64Counter
88+
spanEndedCount metric.Int64Counter
89+
spanLiveCount metric.Int64UpDownCounter
90+
sampledAttributes metric.MeasurementOption
91+
notSampledAttributes metric.MeasurementOption
8292
}
8393

8494
var _ trace.TracerProvider = &TracerProvider{}
@@ -120,9 +130,55 @@ func NewTracerProvider(opts ...TracerProviderOption) *TracerProvider {
120130
}
121131
tp.spanProcessors.Store(&spss)
122132

133+
tp.configureSelfObservability()
134+
123135
return tp
124136
}
125137

138+
var providerID atomic.Uint64
139+
140+
// nextProviderID returns an identifier for this tracerprovider,
141+
// starting with 0 and incrementing by 1 each time it is called.
142+
func nextProviderID() int64 {
143+
return int64(providerID.Add(1) - 1)
144+
}
145+
146+
func (p *TracerProvider) configureSelfObservability() {
147+
mp := otel.GetMeterProvider()
148+
if !x.SelfObservability.Enabled() {
149+
mp = metric.MeterProvider(metricnoop.NewMeterProvider())
150+
}
151+
meter := mp.Meter(
152+
selfObsScopeName,
153+
metric.WithInstrumentationVersion(version()),
154+
)
155+
componentNameAttr := attribute.String("otel.sdk.component.name", fmt.Sprintf("tracer_provider/%d", nextProviderID()))
156+
p.sampledAttributes = metric.WithAttributes(componentNameAttr, attribute.String("otel.span.is_sampled", "true"))
157+
p.notSampledAttributes = metric.WithAttributes(componentNameAttr, attribute.String("otel.span.is_sampled", "false"))
158+
var err error
159+
p.spanCreatedCount, err = meter.Int64Counter("otel.sdk.span.created_count",
160+
metric.WithUnit("{span}"),
161+
metric.WithDescription("The number of spans which have been created."),
162+
)
163+
if err != nil {
164+
otel.Handle(err)
165+
}
166+
p.spanEndedCount, err = meter.Int64Counter("otel.sdk.span.ended_count",
167+
metric.WithUnit("{span}"),
168+
metric.WithDescription("The number of created spans for which the end operation was called."),
169+
)
170+
if err != nil {
171+
otel.Handle(err)
172+
}
173+
p.spanLiveCount, err = meter.Int64UpDownCounter("otel.sdk.span.live_count",
174+
metric.WithUnit("{span}"),
175+
metric.WithDescription("The number of created spans for which the end operation has not been called yet."),
176+
)
177+
if err != nil {
178+
otel.Handle(err)
179+
}
180+
}
181+
126182
// Tracer returns a Tracer with the given name and options. If a Tracer for
127183
// the given name and options does not exist it is created, otherwise the
128184
// existing Tracer is returned.

sdk/trace/span.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,14 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
495495
}
496496
s.mu.Unlock()
497497

498+
if s.spanContext.IsSampled() {
499+
s.tracer.provider.spanLiveCount.Add(context.Background(), -1, s.tracer.provider.sampledAttributes)
500+
s.tracer.provider.spanEndedCount.Add(context.Background(), 1, s.tracer.provider.sampledAttributes)
501+
} else {
502+
s.tracer.provider.spanLiveCount.Add(context.Background(), -1, s.tracer.provider.notSampledAttributes)
503+
s.tracer.provider.spanEndedCount.Add(context.Background(), 1, s.tracer.provider.notSampledAttributes)
504+
}
505+
498506
sps := s.tracer.provider.getSpanProcessors()
499507
if len(sps) == 0 {
500508
return
@@ -901,7 +909,11 @@ func (nonRecordingSpan) SetError(bool) {}
901909
func (nonRecordingSpan) SetAttributes(...attribute.KeyValue) {}
902910

903911
// End does nothing.
904-
func (nonRecordingSpan) End(...trace.SpanEndOption) {}
912+
func (s nonRecordingSpan) End(...trace.SpanEndOption) {
913+
// TODO: does adding instrumentation to non-recording spans have performance implications?
914+
s.tracer.provider.spanEndedCount.Add(context.Background(), 1, s.tracer.provider.notSampledAttributes)
915+
s.tracer.provider.spanLiveCount.Add(context.Background(), -1, s.tracer.provider.notSampledAttributes)
916+
}
905917

906918
// RecordError does nothing.
907919
func (nonRecordingSpan) RecordError(error, ...trace.EventOption) {}

sdk/trace/tracer.go

+4
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,12 @@ func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanCo
100100
}
101101
if isSampled(samplingResult) {
102102
scc.TraceFlags = psc.TraceFlags() | trace.FlagsSampled
103+
tr.provider.spanLiveCount.Add(ctx, 1, tr.provider.sampledAttributes)
104+
tr.provider.spanCreatedCount.Add(ctx, 1, tr.provider.sampledAttributes)
103105
} else {
104106
scc.TraceFlags = psc.TraceFlags() &^ trace.FlagsSampled
107+
tr.provider.spanLiveCount.Add(ctx, 1, tr.provider.notSampledAttributes)
108+
tr.provider.spanCreatedCount.Add(ctx, 1, tr.provider.notSampledAttributes)
105109
}
106110
sc := trace.NewSpanContext(scc)
107111

0 commit comments

Comments
 (0)