You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-11-27 22:49:15 +02:00
Split from #7316
[Follow
guidelines](a5dcd68ebb/CONTRIBUTING.md (encapsulation))
and move instrumentation into its own type.
### Benchmarks
#### Added `sdk/trace/internal/observ` benchmarks
```
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/trace/internal/observ
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
│ enc-trace-sdk-tracer-obs.out │
│ sec/op │
Tracer/SpanStarted-8 7.436n ± 6%
Tracer/SpanLive-8 9.987n ± 8%
Tracer/SpanEnded-8 11.32n ± 7%
NewTracer-8 87.64n ± 6%
geomean 16.48n
│ enc-trace-sdk-tracer-obs.out │
│ B/op │
Tracer/SpanStarted-8 0.000 ± 0%
Tracer/SpanLive-8 0.000 ± 0%
Tracer/SpanEnded-8 0.000 ± 0%
NewTracer-8 0.000 ± 0%
geomean ¹
¹ summaries must be >0 to compute geomean
│ enc-trace-sdk-tracer-obs.out │
│ allocs/op │
Tracer/SpanStarted-8 0.000 ± 0%
Tracer/SpanLive-8 0.000 ± 0%
Tracer/SpanEnded-8 0.000 ± 0%
NewTracer-8 0.000 ± 0%
geomean ¹
¹ summaries must be >0 to compute geomean
```
#### Existing `sdk/trace` benchmarks
```console
> benchstat main.out enc-trace-sdk-tracer-obs.out
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
│ main.out │ enc-trace-sdk-tracer-obs.out │
│ sec/op │ sec/op vs base │
SpanEnd/ObservabilityEnabled-8 188.5n ± 4% 131.5n ± 32% -30.24% (p=0.000 n=10)
TraceStart/ObservabilityEnabled-8 886.9n ± 8% 663.9n ± 2% -25.14% (p=0.000 n=10)
geomean 408.9n 295.5n -27.73%
│ main.out │ enc-trace-sdk-tracer-obs.out │
│ B/op │ B/op vs base │
SpanEnd/ObservabilityEnabled-8 16.00 ± 0% 0.00 ± 0% -100.00% (p=0.000 n=10)
TraceStart/ObservabilityEnabled-8 608.0 ± 0% 576.0 ± 0% -5.26% (p=0.000 n=10)
geomean 98.63 ? ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
│ main.out │ enc-trace-sdk-tracer-obs.out │
│ allocs/op │ allocs/op vs base │
SpanEnd/ObservabilityEnabled-8 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
TraceStart/ObservabilityEnabled-8 5.000 ± 0% 3.000 ± 0% -40.00% (p=0.000 n=10)
geomean 2.236 ? ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
```
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
224 lines
5.6 KiB
Go
224 lines
5.6 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package observ // import "go.opentelemetry.io/otel/sdk/trace/internal/observ"
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/metric"
|
|
"go.opentelemetry.io/otel/sdk"
|
|
"go.opentelemetry.io/otel/sdk/trace/internal/x"
|
|
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
var meterOpts = []metric.MeterOption{
|
|
metric.WithInstrumentationVersion(sdk.Version()),
|
|
metric.WithSchemaURL(SchemaURL),
|
|
}
|
|
|
|
// Tracer is instrumentation for an OTel SDK Tracer.
|
|
type Tracer struct {
|
|
enabled bool
|
|
|
|
live metric.Int64UpDownCounter
|
|
started metric.Int64Counter
|
|
}
|
|
|
|
func NewTracer() (Tracer, error) {
|
|
if !x.Observability.Enabled() {
|
|
return Tracer{}, nil
|
|
}
|
|
meter := otel.GetMeterProvider().Meter(ScopeName, meterOpts...)
|
|
|
|
var err error
|
|
l, e := otelconv.NewSDKSpanLive(meter)
|
|
if e != nil {
|
|
e = fmt.Errorf("failed to create span live metric: %w", e)
|
|
err = errors.Join(err, e)
|
|
}
|
|
|
|
s, e := otelconv.NewSDKSpanStarted(meter)
|
|
if e != nil {
|
|
e = fmt.Errorf("failed to create span started metric: %w", e)
|
|
err = errors.Join(err, e)
|
|
}
|
|
|
|
return Tracer{enabled: true, live: l.Inst(), started: s.Inst()}, err
|
|
}
|
|
|
|
func (t Tracer) Enabled() bool { return t.enabled }
|
|
|
|
func (t Tracer) SpanStarted(ctx context.Context, psc trace.SpanContext, span trace.Span) {
|
|
key := spanStartedKey{
|
|
parent: parentStateNoParent,
|
|
sampling: samplingStateDrop,
|
|
}
|
|
|
|
if psc.IsValid() {
|
|
if psc.IsRemote() {
|
|
key.parent = parentStateRemoteParent
|
|
} else {
|
|
key.parent = parentStateLocalParent
|
|
}
|
|
}
|
|
|
|
if span.IsRecording() {
|
|
if span.SpanContext().IsSampled() {
|
|
key.sampling = samplingStateRecordAndSample
|
|
} else {
|
|
key.sampling = samplingStateRecordOnly
|
|
}
|
|
}
|
|
|
|
opts := spanStartedOpts[key]
|
|
t.started.Add(ctx, 1, opts...)
|
|
}
|
|
|
|
func (t Tracer) SpanLive(ctx context.Context, span trace.Span) {
|
|
t.spanLive(ctx, 1, span)
|
|
}
|
|
|
|
func (t Tracer) SpanEnded(ctx context.Context, span trace.Span) {
|
|
t.spanLive(ctx, -1, span)
|
|
}
|
|
|
|
func (t Tracer) spanLive(ctx context.Context, value int64, span trace.Span) {
|
|
key := spanLiveKey{sampled: span.SpanContext().IsSampled()}
|
|
opts := spanLiveOpts[key]
|
|
t.live.Add(ctx, value, opts...)
|
|
}
|
|
|
|
type parentState int
|
|
|
|
const (
|
|
parentStateNoParent parentState = iota
|
|
parentStateLocalParent
|
|
parentStateRemoteParent
|
|
)
|
|
|
|
type samplingState int
|
|
|
|
const (
|
|
samplingStateDrop samplingState = iota
|
|
samplingStateRecordOnly
|
|
samplingStateRecordAndSample
|
|
)
|
|
|
|
type spanStartedKey struct {
|
|
parent parentState
|
|
sampling samplingState
|
|
}
|
|
|
|
var spanStartedOpts = map[spanStartedKey][]metric.AddOption{
|
|
{
|
|
parentStateNoParent,
|
|
samplingStateDrop,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginNone),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultDrop),
|
|
)),
|
|
},
|
|
{
|
|
parentStateLocalParent,
|
|
samplingStateDrop,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginLocal),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultDrop),
|
|
)),
|
|
},
|
|
{
|
|
parentStateRemoteParent,
|
|
samplingStateDrop,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginRemote),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultDrop),
|
|
)),
|
|
},
|
|
|
|
{
|
|
parentStateNoParent,
|
|
samplingStateRecordOnly,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginNone),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordOnly),
|
|
)),
|
|
},
|
|
{
|
|
parentStateLocalParent,
|
|
samplingStateRecordOnly,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginLocal),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordOnly),
|
|
)),
|
|
},
|
|
{
|
|
parentStateRemoteParent,
|
|
samplingStateRecordOnly,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginRemote),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordOnly),
|
|
)),
|
|
},
|
|
|
|
{
|
|
parentStateNoParent,
|
|
samplingStateRecordAndSample,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginNone),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordAndSample),
|
|
)),
|
|
},
|
|
{
|
|
parentStateLocalParent,
|
|
samplingStateRecordAndSample,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginLocal),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordAndSample),
|
|
)),
|
|
},
|
|
{
|
|
parentStateRemoteParent,
|
|
samplingStateRecordAndSample,
|
|
}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanStarted{}.AttrSpanParentOrigin(otelconv.SpanParentOriginRemote),
|
|
otelconv.SDKSpanStarted{}.AttrSpanSamplingResult(otelconv.SpanSamplingResultRecordAndSample),
|
|
)),
|
|
},
|
|
}
|
|
|
|
type spanLiveKey struct {
|
|
sampled bool
|
|
}
|
|
|
|
var spanLiveOpts = map[spanLiveKey][]metric.AddOption{
|
|
{true}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanLive{}.AttrSpanSamplingResult(
|
|
otelconv.SpanSamplingResultRecordAndSample,
|
|
),
|
|
)),
|
|
},
|
|
{false}: {
|
|
metric.WithAttributeSet(attribute.NewSet(
|
|
otelconv.SDKSpanLive{}.AttrSpanSamplingResult(
|
|
otelconv.SpanSamplingResultRecordOnly,
|
|
),
|
|
)),
|
|
},
|
|
}
|