1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-11-29 23:07:45 +02:00

Encapsulate observability in Logs SDK (#7315)

- [Follow
guidelines](a5dcd68ebb/CONTRIBUTING.md (encapsulation))
and encapsulate the Observability for the Logs SDK logger by moving it
into a single function.
- Add benchmarks to ensure no performance regressions

### Benchmarks

```console
$ benchstat main_2de26d1de.txt enc-sdk-log-obs_c06e888.txt
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/log
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
                                   │ main_2de26d1de.txt │    enc-sdk-log-obs_c06e888.txt     │
                                   │       sec/op       │   sec/op     vs base               │
LoggerEmitObservability/Disabled-8          167.8n ± 4%   167.3n ± 5%       ~ (p=0.796 n=10)
LoggerEmitObservability/Enabled-8           556.6n ± 4%   556.1n ± 4%       ~ (p=0.955 n=10)
geomean                                     305.6n        305.0n       -0.19%

                                   │ main_2de26d1de.txt │     enc-sdk-log-obs_c06e888.txt     │
                                   │        B/op        │    B/op     vs base                 │
LoggerEmitObservability/Disabled-8           448.0 ± 0%   448.0 ± 0%       ~ (p=1.000 n=10) ¹
LoggerEmitObservability/Enabled-8            448.0 ± 0%   448.0 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                      448.0        448.0       +0.00%
¹ all samples are equal

                                   │ main_2de26d1de.txt │     enc-sdk-log-obs_c06e888.txt     │
                                   │     allocs/op      │ allocs/op   vs base                 │
LoggerEmitObservability/Disabled-8           1.000 ± 0%   1.000 ± 0%       ~ (p=1.000 n=10) ¹
LoggerEmitObservability/Enabled-8            1.000 ± 0%   1.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                      1.000        1.000       +0.00%
¹ all samples are equal
```
This commit is contained in:
Tyler Yahn
2025-09-08 07:29:01 -07:00
committed by GitHub
parent dcf14aa937
commit b335c0795c
3 changed files with 88 additions and 20 deletions

View File

@@ -0,0 +1,39 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package log // import "go.opentelemetry.io/otel/sdk/log"
import (
"context"
"fmt"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/log/internal/x"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
)
// newRecordCounterIncr returns a function that increments the log record
// counter metric. If observability is disabled, it returns nil.
func newRecordCounterIncr() (func(context.Context), error) {
if !x.SelfObservability.Enabled() {
return nil, nil
}
m := otel.GetMeterProvider().Meter(
"go.opentelemetry.io/otel/sdk/log",
metric.WithInstrumentationVersion(sdk.Version()),
metric.WithSchemaURL(semconv.SchemaURL),
)
created, err := otelconv.NewSDKLogCreated(m)
if err != nil {
err = fmt.Errorf("failed to create log created metric: %w", err)
return nil, err
}
inst := created.Inst()
f := func(ctx context.Context) { inst.Add(ctx, 1) }
return f, nil
}

View File

@@ -5,18 +5,12 @@ package log // import "go.opentelemetry.io/otel/sdk/log"
import (
"context"
"fmt"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/embedded"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/log/internal/x"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
"go.opentelemetry.io/otel/trace"
)
@@ -31,8 +25,9 @@ type logger struct {
provider *LoggerProvider
instrumentationScope instrumentation.Scope
selfObservabilityEnabled bool
logCreatedMetric otelconv.SDKLogCreated
// recCntIncr increments the count of log records created. It will be nil
// if observability is disabled.
recCntIncr func(context.Context)
}
func newLogger(p *LoggerProvider, scope instrumentation.Scope) *logger {
@@ -40,18 +35,10 @@ func newLogger(p *LoggerProvider, scope instrumentation.Scope) *logger {
provider: p,
instrumentationScope: scope,
}
if !x.SelfObservability.Enabled() {
return l
}
l.selfObservabilityEnabled = true
mp := otel.GetMeterProvider()
m := mp.Meter("go.opentelemetry.io/otel/sdk/log",
metric.WithInstrumentationVersion(sdk.Version()),
metric.WithSchemaURL(semconv.SchemaURL))
var err error
if l.logCreatedMetric, err = otelconv.NewSDKLogCreated(m); err != nil {
err = fmt.Errorf("failed to create log created metric: %w", err)
l.recCntIncr, err = newRecordCounterIncr()
if err != nil {
otel.Handle(err)
}
return l
@@ -119,8 +106,8 @@ func (l *logger) newRecord(ctx context.Context, r log.Record) Record {
attributeCountLimit: l.provider.attributeCountLimit,
allowDupKeys: l.provider.allowDupKeys,
}
if l.selfObservabilityEnabled {
l.logCreatedMetric.Add(ctx, 1)
if l.recCntIncr != nil {
l.recCntIncr(ctx)
}
// This ensures we deduplicate key-value collections in the log body

View File

@@ -10,7 +10,11 @@ import (
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/sdk/instrumentation"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)
func BenchmarkLoggerEmit(b *testing.B) {
@@ -62,6 +66,44 @@ func BenchmarkLoggerEmit(b *testing.B) {
})
}
func BenchmarkLoggerEmitObservability(b *testing.B) {
r := log.Record{}
orig := otel.GetMeterProvider()
b.Cleanup(func() { otel.SetMeterProvider(orig) })
reader := metric.NewManualReader()
mp := metric.NewMeterProvider(metric.WithReader(reader))
otel.SetMeterProvider(mp)
run := func(logger *logger) func(b *testing.B) {
return func(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Emit(context.Background(), r)
}
})
}
}
lp := NewLoggerProvider()
scope := instrumentation.Scope{}
b.Run("Disabled", run(newLogger(lp, scope)))
b.Run("Enabled", func(b *testing.B) {
b.Setenv("OTEL_GO_X_SELF_OBSERVABILITY", "true")
run(newLogger(lp, scope))(b)
})
var rm metricdata.ResourceMetrics
err := reader.Collect(context.Background(), &rm)
require.NoError(b, err)
require.Len(b, rm.ScopeMetrics, 1)
}
func BenchmarkLoggerEnabled(b *testing.B) {
logger := newTestLogger(b)
ctx := context.Background()