You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2026-06-03 18:35:08 +02:00
5da6cd28a8
Closes #5133 This couldn't be added as an option on a processor, as that would involve moving all the attribute deduplication. logic outside of the record type. Instead this PR provides the same functionality but it is set when creating the log provider The below benchstat report shows the performance improvement when `allowDupKeys` is set ``` goos: darwin goarch: arm64 pkg: go.opentelemetry.io/otel/sdk/log cpu: Apple M2 Pro │ withoutDedup.txt │ withDedup.txt │ │ sec/op │ sec/op vs base │ SetAddAttributes/SetAttributes-12 141.3n ± 2% 167.4n ± 5% +18.51% (p=0.000 n=10) SetAddAttributes/AddAttributes-12 117.5n ± 2% 124.8n ± 5% +6.17% (p=0.000 n=10) geomean 128.9n 144.5n +12.17% │ withoutDedup.txt │ withDedup.txt │ │ B/op │ B/op vs base │ SetAddAttributes/SetAttributes-12 48.00 ± 0% 48.00 ± 0% ~ (p=1.000 n=10) ¹ SetAddAttributes/AddAttributes-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ withoutDedup.txt │ withDedup.txt │ │ allocs/op │ allocs/op vs base │ SetAddAttributes/SetAttributes-12 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ SetAddAttributes/AddAttributes-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ```
112 lines
3.2 KiB
Go
112 lines
3.2 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package log // import "go.opentelemetry.io/otel/sdk/log"
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/log"
|
|
"go.opentelemetry.io/otel/log/embedded"
|
|
"go.opentelemetry.io/otel/sdk/instrumentation"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
var now = time.Now
|
|
|
|
// Compile-time check logger implements log.Logger.
|
|
var _ log.Logger = (*logger)(nil)
|
|
|
|
type logger struct {
|
|
embedded.Logger
|
|
|
|
provider *LoggerProvider
|
|
instrumentationScope instrumentation.Scope
|
|
}
|
|
|
|
func newLogger(p *LoggerProvider, scope instrumentation.Scope) *logger {
|
|
return &logger{
|
|
provider: p,
|
|
instrumentationScope: scope,
|
|
}
|
|
}
|
|
|
|
func (l *logger) Emit(ctx context.Context, r log.Record) {
|
|
newRecord := l.newRecord(ctx, r)
|
|
for _, p := range l.provider.processors {
|
|
if err := p.OnEmit(ctx, &newRecord); err != nil {
|
|
otel.Handle(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enabled returns true if at least one Processor held by the LoggerProvider
|
|
// that created the logger will process param for the provided context and param.
|
|
//
|
|
// If it is not possible to definitively determine the param will be
|
|
// processed, true will be returned by default. A value of false will only be
|
|
// returned if it can be positively verified that no Processor will process.
|
|
func (l *logger) Enabled(ctx context.Context, param log.EnabledParameters) bool {
|
|
p := EnabledParameters{
|
|
InstrumentationScope: l.instrumentationScope,
|
|
Severity: param.Severity,
|
|
EventName: param.EventName,
|
|
}
|
|
|
|
// If there are more Processors than FilterProcessors,
|
|
// which means not all Processors are FilterProcessors,
|
|
// we cannot be sure that all Processors will drop the record.
|
|
// Therefore, return true.
|
|
//
|
|
// If all Processors are FilterProcessors, check if any is enabled.
|
|
return len(l.provider.processors) > len(l.provider.fltrProcessors) || anyEnabled(ctx, p, l.provider.fltrProcessors)
|
|
}
|
|
|
|
func anyEnabled(ctx context.Context, param EnabledParameters, fltrs []FilterProcessor) bool {
|
|
for _, f := range fltrs {
|
|
if f.Enabled(ctx, param) {
|
|
// At least one Processor will process the Record.
|
|
return true
|
|
}
|
|
}
|
|
// No Processor will process the record
|
|
return false
|
|
}
|
|
|
|
func (l *logger) newRecord(ctx context.Context, r log.Record) Record {
|
|
sc := trace.SpanContextFromContext(ctx)
|
|
|
|
newRecord := Record{
|
|
eventName: r.EventName(),
|
|
timestamp: r.Timestamp(),
|
|
observedTimestamp: r.ObservedTimestamp(),
|
|
severity: r.Severity(),
|
|
severityText: r.SeverityText(),
|
|
body: r.Body(),
|
|
|
|
traceID: sc.TraceID(),
|
|
spanID: sc.SpanID(),
|
|
traceFlags: sc.TraceFlags(),
|
|
|
|
resource: l.provider.resource,
|
|
scope: &l.instrumentationScope,
|
|
attributeValueLengthLimit: l.provider.attributeValueLengthLimit,
|
|
attributeCountLimit: l.provider.attributeCountLimit,
|
|
allowDupKeys: l.provider.allowDupKeys,
|
|
}
|
|
|
|
// This field SHOULD be set once the event is observed by OpenTelemetry.
|
|
if newRecord.observedTimestamp.IsZero() {
|
|
newRecord.observedTimestamp = now()
|
|
}
|
|
|
|
r.WalkAttributes(func(kv log.KeyValue) bool {
|
|
newRecord.AddAttributes(kv)
|
|
return true
|
|
})
|
|
|
|
return newRecord
|
|
}
|