uniform
Build and Publish / BuildAndDeployArm64 (push) Failing after 7s
Build and Publish / BuildAndDeployAmd64 (push) Failing after 7s

This commit is contained in:
2026-07-20 00:13:24 +02:00
parent 83ed477aa4
commit e6f69f500a
14 changed files with 457 additions and 471 deletions
+36 -40
View File
@@ -12,22 +12,42 @@ import (
"go.opentelemetry.io/otel/sdk/log"
)
// NewLoggerProvider builds the OTLP log provider from the environment, or returns
// (nil, nil) when logs are disabled — in which case the caller MUST skip
// LoggerConfig controls the optional OTLP log pipeline.
// The zero value disables logging (Enabled = false, SampleRatio = 0).
type LoggerConfig struct {
Enabled bool
SampleRatio float64 // 0.01.0, clamped by NewLoggerProvider
}
// LoggerConfigFromEnv reads OTEL_LOGS_ENABLED and OTEL_LOGS_SAMPLE_RATIO from
// the environment. Call this from main(); library consumers that want explicit
// control should construct LoggerConfig directly.
func LoggerConfigFromEnv() LoggerConfig {
var enabled bool
switch os.Getenv("OTEL_LOGS_ENABLED") {
case "1", "true", "TRUE", "True", "yes", "on":
enabled = true
}
ratio := 1.0
if v := os.Getenv("OTEL_LOGS_SAMPLE_RATIO"); v != "" {
if r, err := strconv.ParseFloat(v, 64); err == nil && r >= 0 && r <= 1 {
ratio = r
}
}
return LoggerConfig{Enabled: enabled, SampleRatio: ratio}
}
// NewLoggerProvider builds the OTLP log provider from cfg, or returns
// (nil, nil) when cfg.Enabled is false — in which case the caller MUST skip
// global.SetLoggerProvider and the shutdown registration.
//
// Env:
//
// OTEL_LOGS_ENABLED "1"/"true"/"yes"/"on" to enable the OTLP log pipeline.
// Default OFF: the batch processor clones its record ring
// on every export, which profiling showed to be the
// dominant heap allocator in these services. Traces and
// metrics are always on regardless of this flag.
// OTEL_LOGS_SAMPLE_RATIO fraction of records to export, 0.01.0 (default 1.0).
// e.g. 0.1 keeps ~10% of logs. Dropped records never reach
// the batch ring, so allocation churn falls ~proportionally.
func NewLoggerProvider(ctx context.Context) (*log.LoggerProvider, error) {
if !logsEnabled() {
// Use LoggerConfigFromEnv() to read the conventional OTEL_LOGS_ENABLED /
// OTEL_LOGS_SAMPLE_RATIO env vars, or construct LoggerConfig directly for
// explicit control (e.g. tests). Default OFF: the batch processor clones its
// record ring on every export, which profiling showed to be the dominant heap
// allocator in these services. Traces and metrics are always on regardless.
func NewLoggerProvider(ctx context.Context, cfg LoggerConfig) (*log.LoggerProvider, error) {
if !cfg.Enabled {
return nil, nil
}
exporter, err := otlploggrpc.New(ctx)
@@ -35,36 +55,12 @@ func NewLoggerProvider(ctx context.Context) (*log.LoggerProvider, error) {
return nil, err
}
var proc log.Processor = log.NewBatchProcessor(exporter)
if ratio := sampleRatio(); ratio < 1.0 {
proc = &samplingProcessor{next: proc, ratio: ratio}
if cfg.SampleRatio < 1.0 {
proc = &samplingProcessor{next: proc, ratio: cfg.SampleRatio}
}
return log.NewLoggerProvider(log.WithProcessor(proc)), nil
}
func logsEnabled() bool {
switch os.Getenv("OTEL_LOGS_ENABLED") {
case "1", "true", "TRUE", "True", "yes", "on":
return true
default:
return false
}
}
func sampleRatio() float64 {
v := os.Getenv("OTEL_LOGS_SAMPLE_RATIO")
if v == "" {
return 1.0
}
r, err := strconv.ParseFloat(v, 64)
if err != nil || r < 0 {
return 1.0
}
if r > 1 {
return 1.0
}
return r
}
// samplingProcessor forwards a random `ratio` fraction of records to the wrapped
// processor and drops the rest before they reach the (allocation-heavy) batch
// ring. This is head sampling: cheap, stateless, and per-record independent.