Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spike] MultiLoggerProvider #5830

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions sdk/log/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,44 @@ func (p *RedactTokensProcessor) Shutdown(ctx context.Context) error {
func (p *RedactTokensProcessor) ForceFlush(ctx context.Context) error {
return nil
}

func ExampleMultiLoggerProvider() {
// Set up a pipeline that emits redacted logs via OTLP with batching.
var otlpExporter log.Exporter // exporter, err := otlploghttp.New(ctx)
redactProcessor := &RedactTokensProcessor{}
processor := log.NewBatchProcessor(otlpExporter)
provider1 := log.NewLoggerProvider(
log.WithProcessor(redactProcessor),
log.WithProcessor(processor),
)
defer func() {
err := provider1.Shutdown(context.Background())
if err != nil {
fmt.Println(err)
}
}()

// Set up a pipeline that synchrnously emits logs to stdout.
var stdoutExporter log.Exporter // exporter, err := stdoutlog.New(ctx)
provider2 := log.NewLoggerProvider(
log.WithProcessor(
log.NewSimpleProcessor(stdoutExporter),
),
)
defer func() {
err := provider2.Shutdown(context.Background())
if err != nil {
fmt.Println(err)
}
}()

// Create a multi provider which handles both pipelines.
multiProvider := log.MultiLoggerProvider(provider1, provider2)

// Register as global logger provider so that it can be used via global.Meter
// and accessed using global.GetMeterProvider.
// Most log bridges use the global logger provider as default.
// If the global logger provider is not set then a no-op implementation
// is used, which fails to generate data.
global.SetLoggerProvider(multiProvider)
}
62 changes: 62 additions & 0 deletions sdk/log/multi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package log // import "go.opentelemetry.io/otel/sdk/log"

import (
"context"

"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/embedded"
)

type multiLoggerProvider struct {
embedded.LoggerProvider

providers []log.LoggerProvider

noCmp [0]func() //nolint: unused // This is indeed used.
}

// MultiLoggerProvider returns a composite (fan-out) provider.
// It duplicates its calls to all the passed providers.
// It can be used to set up multiple processing pipelines.
// For instance, you can have separate providers for OTel events
// and application logs.
func MultiLoggerProvider(providers ...log.LoggerProvider) log.LoggerProvider {
return &multiLoggerProvider{
providers: providers,
}
}

// Logger returns a logger delegating to loggers created by all providers.
func (p *multiLoggerProvider) Logger(name string, opts ...log.LoggerOption) log.Logger {
var loggers []log.Logger
for _, p := range p.providers {
loggers = append(loggers, p.Logger(name, opts...))
}
return &multiLogger{loggers: loggers}
}

type multiLogger struct {
embedded.Logger

loggers []log.Logger

noCmp [0]func() //nolint: unused // This is indeed used.
}

func (l *multiLogger) Emit(ctx context.Context, r log.Record) {
for _, l := range l.loggers {
l.Emit(ctx, r)
}
}

func (l *multiLogger) Enabled(ctx context.Context, param log.EnabledParameters) bool {
for _, l := range l.loggers {
if !l.Enabled(ctx, param) {
return false
}
}
return true
}
Loading