The OpenTelemetry Go SDK log implementation provides concrete implementations of the log API interfaces, including LoggerProvider, processors, and exporters. Note: The logging signal is currently in beta status.
import sdklog "go.opentelemetry.io/otel/sdk/log"The SDK log package provides:
The LoggerProvider is the SDK implementation of the log.LoggerProvider interface.
type LoggerProvider struct {
// Has unexported fields
}func NewLoggerProvider(opts ...LoggerProviderOption) *LoggerProviderDefault Configuration:
Example:
package main
import (
"context"
"log"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)
func main() {
ctx := context.Background()
// Create resource
res, err := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceName("my-service"),
semconv.ServiceVersion("1.0.0"),
),
)
if err != nil {
log.Fatal(err)
}
// Create exporter
exporter, err := otlploghttp.New(ctx)
if err != nil {
log.Fatal(err)
}
// Create processor
processor := log.NewBatchProcessor(exporter)
// Create logger provider
lp := log.NewLoggerProvider(
log.WithResource(res),
log.WithProcessor(processor),
)
// Set as global logger provider
global.SetLoggerProvider(lp)
// Cleanup
defer func() {
if err := lp.Shutdown(ctx); err != nil {
log.Printf("Error shutting down logger provider: %v", err)
}
}()
// Use logger
logger := global.GetLoggerProvider().Logger("my-component")
// Emit log records...
}// Logger returns a Logger with the given name and options
func (p *LoggerProvider) Logger(name string, opts ...log.LoggerOption) log.Logger
// Shutdown shuts down the LoggerProvider and all processors
func (p *LoggerProvider) Shutdown(ctx context.Context) error
// ForceFlush flushes all processors
func (p *LoggerProvider) ForceFlush(ctx context.Context) errorOptions for configuring a LoggerProvider.
type LoggerProviderOption interface {
// Has unexported methods
}Available Options:
// WithResource configures the Resource for the LoggerProvider
func WithResource(res *resource.Resource) LoggerProviderOption
// WithProcessor registers a Processor with the LoggerProvider
func WithProcessor(processor Processor) LoggerProviderOption
// WithAttributeCountLimit sets the maximum allowed log record attribute count
// Any attribute added to a log record once this limit is reached will be dropped
// Setting this to zero means no attributes will be recorded
// Setting this to a negative value means no limit is applied
// Default: 128 (or value from OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT env var)
func WithAttributeCountLimit(limit int) LoggerProviderOption
// WithAttributeValueLengthLimit sets the maximum allowed attribute value length
// This limit only applies to string and string slice attribute values
// Any string longer than this value will be truncated
// Setting this to a negative value means no limit is applied
// Default: -1 unlimited (or value from OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT env var)
func WithAttributeValueLengthLimit(limit int) LoggerProviderOption
// WithAllowKeyDuplication sets whether deduplication is skipped for log attributes
// By default, key-value collections are deduplicated (only last value kept for duplicate keys)
// Disabling deduplication can improve performance but requires ensuring no duplicate keys
func WithAllowKeyDuplication() LoggerProviderOptionExample:
lp := sdklog.NewLoggerProvider(
sdklog.WithResource(res),
sdklog.WithProcessor(processor),
sdklog.WithAttributeCountLimit(200),
sdklog.WithAttributeValueLengthLimit(4096),
sdklog.WithAllowKeyDuplication(),
)Processors process log records before they are exported.
type Processor interface {
// OnEmit is called when a log record is emitted
OnEmit(ctx context.Context, record *Record) error
// Enabled returns whether the processor is enabled for the given context and record
Enabled(ctx context.Context, record Record) bool
// Shutdown shuts down the processor
Shutdown(ctx context.Context) error
// ForceFlush flushes all log records
ForceFlush(ctx context.Context) error
}BatchProcessor batches log records and exports them in batches.
func NewBatchProcessor(exporter Exporter, opts ...BatchProcessorOption) *BatchProcessorDefault Configuration:
Example:
import (
"time"
"go.opentelemetry.io/otel/exporters/stdout/stdoutlog"
sdklog "go.opentelemetry.io/otel/sdk/log"
)
func setupBatchProcessor() *sdklog.BatchProcessor {
exporter, err := stdoutlog.New()
if err != nil {
log.Fatal(err)
}
processor := sdklog.NewBatchProcessor(
exporter,
sdklog.WithMaxQueueSize(4096),
sdklog.WithExportInterval(5*time.Second),
sdklog.WithExportTimeout(30*time.Second),
sdklog.WithExportMaxBatchSize(1024),
)
return processor
}Options for configuring a BatchProcessor.
type BatchProcessorOption func(*BatchProcessor)Available Options:
// WithMaxQueueSize sets the maximum queue size
func WithMaxQueueSize(size int) BatchProcessorOption
// WithExportInterval sets the interval between exports
func WithExportInterval(d time.Duration) BatchProcessorOption
// WithExportTimeout sets the maximum duration for exporting
func WithExportTimeout(d time.Duration) BatchProcessorOption
// WithExportMaxBatchSize sets the maximum batch size
func WithExportMaxBatchSize(size int) BatchProcessorOption
// WithExportBufferSize sets the batch buffer size
// Batches will be temporarily kept in memory buffer until exported
// Default: 1
func WithExportBufferSize(size int) BatchProcessorOptionSimpleProcessor exports log records synchronously when they are emitted. Not recommended for production use.
func NewSimpleProcessor(exporter Exporter, opts ...SimpleProcessorOption) *SimpleProcessorExample:
import (
"go.opentelemetry.io/otel/exporters/stdout/stdoutlog"
sdklog "go.opentelemetry.io/otel/sdk/log"
)
func setupSimpleProcessor() *sdklog.SimpleProcessor {
exporter, err := stdoutlog.New()
if err != nil {
log.Fatal(err)
}
// Only use for testing/debugging
processor := sdklog.NewSimpleProcessor(exporter)
return processor
}Options for configuring a SimpleProcessor.
type SimpleProcessorOption interface {
// Has unexported methods
}FilterProcessor extends the Processor interface to allow processors to report whether they will process a given log record. This enables Logger.Enabled to return false when all processors would drop the record.
type FilterProcessor interface {
// Enabled reports whether the Processor will process for the given context and param
// Returns true when the Processor will process the log record
// Returns false if the Processor will drop the log record
Enabled(ctx context.Context, param EnabledParameters) bool
}Use Case: Filtering log records by severity level before expensive operations.
Example:
// See go.opentelemetry.io/contrib/processors/minsev for a reference implementation
// that filters out records below a minimum severity thresholdEnabledParameters provides information for FilterProcessor.Enabled method.
type EnabledParameters struct {
InstrumentationScope instrumentation.Scope
Severity log.Severity
EventName string
}Note: EnabledParameters may contain partial record information. Processors should handle cases where not all fields are populated.
Exporters send log records to external systems.
type Exporter interface {
// Export serializes and transmits log records
Export(ctx context.Context, records []Record) error
// Shutdown flushes all log records and releases resources
Shutdown(ctx context.Context) error
// ForceFlush flushes any log records held by the exporter
ForceFlush(ctx context.Context) error
}Record represents a log record.
type Record struct {
// Timestamp is the time when the log record was created
Timestamp time.Time
// ObservedTimestamp is the time when the log record was observed
ObservedTimestamp time.Time
// Severity is the severity of the log record
Severity log.Severity
// SeverityText is the severity text
SeverityText string
// Body is the body of the log record
Body log.Value
// Attributes are the attributes associated with the log record
Attributes []log.KeyValue
// TraceID is the trace ID associated with the log record
TraceID trace.TraceID
// SpanID is the span ID associated with the log record
SpanID trace.SpanID
// TraceFlags are the trace flags
TraceFlags trace.TraceFlags
// Resource is the resource associated with the log record
Resource *resource.Resource
// InstrumentationScope is the instrumentation scope
InstrumentationScope instrumentation.Scope
// DroppedAttributes is the number of dropped attributes
DroppedAttributes int
}package main
import (
"context"
"log"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
sdklog "go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/trace"
)
func main() {
ctx := context.Background()
// Step 1: Create resource
res, err := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceName("my-service"),
semconv.ServiceVersion("1.0.0"),
),
)
if err != nil {
log.Fatalf("Failed to create resource: %v", err)
}
// Step 2: Create exporter
exporter, err := otlploghttp.New(ctx,
otlploghttp.WithEndpoint("localhost:4318"),
otlploghttp.WithInsecure(),
)
if err != nil {
log.Fatalf("Failed to create exporter: %v", err)
}
// Step 3: Create processor
processor := sdklog.NewBatchProcessor(
exporter,
sdklog.WithMaxQueueSize(4096),
sdklog.WithExportInterval(5*time.Second),
sdklog.WithExportTimeout(30*time.Second),
sdklog.WithExportMaxBatchSize(512),
)
// Step 4: Create logger provider
lp := sdklog.NewLoggerProvider(
sdklog.WithResource(res),
sdklog.WithProcessor(processor),
)
// Step 5: Set as global provider
global.SetLoggerProvider(lp)
// Step 6: Setup cleanup
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := lp.ForceFlush(ctx); err != nil {
log.Printf("Failed to flush logs: %v", err)
}
if err := lp.Shutdown(ctx); err != nil {
log.Printf("Failed to shutdown logger provider: %v", err)
}
}()
// Step 7: Use logger
logger := global.GetLoggerProvider().Logger("my-component")
// Emit log records
var record log.Record
record.SetTimestamp(time.Now())
record.SetObservedTimestamp(time.Now())
record.SetSeverity(log.SeverityInfo)
record.SetSeverityText("INFO")
record.SetBody(log.StringValue("Application started"))
record.AddAttributes(
log.String("environment", "production"),
log.Int("port", 8080),
)
// Add trace context if available
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
record.SetTraceID(span.SpanContext().TraceID())
record.SetSpanID(span.SpanContext().SpanID())
record.SetTraceFlags(span.SpanContext().TraceFlags())
}
logger.Emit(ctx, record)
}The SDK respects the following environment variables:
# Maximum number of attributes per log record
OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT=128
# Maximum attribute value length (-1 for unlimited)
OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT=-1
# Batch processor maximum queue size
OTEL_BLRP_MAX_QUEUE_SIZE=2048
# Batch processor export interval in milliseconds
OTEL_BLRP_SCHEDULE_DELAY=1000
# Batch processor export timeout in milliseconds
OTEL_BLRP_EXPORT_TIMEOUT=30000
# Batch processor maximum export batch size
OTEL_BLRP_MAX_EXPORT_BATCH_SIZE=512// Good: Use batch processor
processor := sdklog.NewBatchProcessor(exporter)
// Bad: Don't use simple processor in production
processor := sdklog.NewSimpleProcessor(exporter) // Synchronous, slowlp := sdklog.NewLoggerProvider(/*...*/)
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := lp.Shutdown(ctx); err != nil {
log.Printf("Error shutting down: %v", err)
}
}()// Add trace context to correlate logs with traces
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
record.SetTraceID(span.SpanContext().TraceID())
record.SetSpanID(span.SpanContext().SpanID())
record.SetTraceFlags(span.SpanContext().TraceFlags())
}lp := sdklog.NewLoggerProvider(
sdklog.WithResource(res),
sdklog.WithProcessor(processor),
// Limits are configured via environment variables or code
)