Skip to content

Commit 18534c3

Browse files
committed
add OTEL_GO_X_SELF_OBSERVABILITY feature gate, and otel.sdk.batch_span_processor.queue_size metric
1 parent 5363a52 commit 18534c3

File tree

5 files changed

+70
-3
lines changed

5 files changed

+70
-3
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1010

1111
### Added
1212

13+
- Add OTEL_GO_X_SELF_OBSERVABILITY environment variable to control whether self-observability metrics and traces are produced by SDKs.
14+
- Add experimental otel.sdk.batch_span_processor.queue_size metric to the trace batch span processor.
15+
16+
### Fixed
17+
1318
- Add `ValueFromAttribute` and `KeyValueFromAttribute` in `go.opentelemetry.io/otel/log`. (#6180)
1419
- Add `EventName` and `SetEventName` to `Record` in `go.opentelemetry.io/otel/log`. (#6187)
1520
- Add `EventName` to `RecordFactory` in `go.opentelemetry.io/otel/log/logtest`. (#6187)

sdk/internal/x/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ All other values are ignored.
2222
[OpenTelemetry resource semantic conventions]: https://opentelemetry.io/docs/specs/semconv/resource/
2323
[resource detectors]: https://pkg.go.dev/go.opentelemetry.io/otel/sdk/resource#Detector
2424

25+
### SDK Self-Observability
26+
27+
To enable experimental metric and trace instrumentation in SDKs, set the `OTEL_GO_X_SELF_OBSERVABILITY` environment variable.
28+
If enabled, this instrumentation uses the global `TracerProvider` and `MeterProvider`.
29+
The value set must be the case-insensitive string of `"true"` to enable the feature.
30+
All other values are ignored.
31+
2532
#### Examples
2633

2734
Enable experimental resource semantic conventions.

sdk/internal/x/x.go

+13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ var Resource = newFeature("RESOURCE", func(v string) (string, bool) {
2525
return "", false
2626
})
2727

28+
// SelfObservability is an experimental feature flag that determines if SDK
29+
// self-observability metrics are enabled.
30+
//
31+
// To enable this feature set the OTEL_GO_X_SELF_OBSERVABILITY environment variable
32+
// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
33+
// will also enable this).
34+
var SelfObservability = newFeature("SELF_OBSERVABILITY", func(v string) (string, bool) {
35+
if strings.ToLower(v) == "true" {
36+
return v, true
37+
}
38+
return "", false
39+
})
40+
2841
// Feature is an experimental feature control flag. It provides a uniform way
2942
// to interact with these feature flags and parse their values.
3043
type Feature[T any] struct {

sdk/trace/batch_span_processor.go

+44-3
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace"
55

66
import (
77
"context"
8+
"errors"
9+
"fmt"
810
"sync"
911
"sync/atomic"
1012
"time"
1113

1214
"go.opentelemetry.io/otel"
15+
"go.opentelemetry.io/otel/attribute"
1316
"go.opentelemetry.io/otel/internal/global"
17+
"go.opentelemetry.io/otel/metric"
18+
"go.opentelemetry.io/otel/metric/noop"
1419
"go.opentelemetry.io/otel/sdk/internal/env"
20+
"go.opentelemetry.io/otel/sdk/internal/x"
1521
"go.opentelemetry.io/otel/trace"
1622
)
1723

@@ -63,8 +69,9 @@ type batchSpanProcessor struct {
6369
e SpanExporter
6470
o BatchSpanProcessorOptions
6571

66-
queue chan ReadOnlySpan
67-
dropped uint32
72+
queue chan ReadOnlySpan
73+
dropped uint32
74+
callbackRegistration metric.Registration
6875

6976
batch []ReadOnlySpan
7077
batchMutex sync.Mutex
@@ -111,6 +118,8 @@ func NewBatchSpanProcessor(exporter SpanExporter, options ...BatchSpanProcessorO
111118
stopCh: make(chan struct{}),
112119
}
113120

121+
bsp.configureSelfObservability()
122+
114123
bsp.stopWait.Add(1)
115124
go func() {
116125
defer bsp.stopWait.Done()
@@ -121,6 +130,38 @@ func NewBatchSpanProcessor(exporter SpanExporter, options ...BatchSpanProcessorO
121130
return bsp
122131
}
123132

133+
func (bsp *batchSpanProcessor) configureSelfObservability() {
134+
mp := otel.GetMeterProvider()
135+
if !x.SelfObservability.Enabled() {
136+
mp = metric.MeterProvider(noop.NewMeterProvider())
137+
}
138+
meter := mp.Meter(
139+
selfObsScopeName,
140+
metric.WithInstrumentationVersion(version()),
141+
)
142+
143+
queueSizeCounter, err := meter.Int64ObservableUpDownCounter("otel.sdk.span.processor.queue_size",
144+
metric.WithUnit("{span}"),
145+
metric.WithDescription("The number of spans in the queue of a given instance of an SDK span processor."),
146+
)
147+
if err != nil {
148+
otel.Handle(err)
149+
}
150+
151+
attrsOpt := metric.WithAttributes(
152+
attribute.String("otel.sdk.component.name", fmt.Sprintf("batching_span_processor/%p", bsp)),
153+
)
154+
bsp.callbackRegistration, err = meter.RegisterCallback(
155+
func(ctx context.Context, o metric.Observer) error {
156+
o.ObserveInt64(queueSizeCounter, int64(len(bsp.queue)), attrsOpt)
157+
return nil
158+
},
159+
queueSizeCounter)
160+
if err != nil {
161+
otel.Handle(err)
162+
}
163+
}
164+
124165
// OnStart method does nothing.
125166
func (bsp *batchSpanProcessor) OnStart(parent context.Context, s ReadWriteSpan) {}
126167

@@ -162,7 +203,7 @@ func (bsp *batchSpanProcessor) Shutdown(ctx context.Context) error {
162203
err = ctx.Err()
163204
}
164205
})
165-
return err
206+
return errors.Join(err, bsp.callbackRegistration.Unregister())
166207
}
167208

168209
type forceFlushSpan struct {

sdk/trace/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
const (
2222
defaultTracerName = "go.opentelemetry.io/otel/sdk/tracer"
23+
selfObsScopeName = "go.opentelemetry.io/otel/sdk/trace"
2324
)
2425

2526
// tracerProviderConfig.

0 commit comments

Comments
 (0)