or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

attributes.mdbridges.mdcontext-propagation.mdexporters-other.mdexporters-otlp.mdindex.mdlogging.mdmetrics.mdsdk-log.mdsdk-metric.mdsdk-resource.mdsdk-trace.mdsemantic-conventions.mdtracing.md
tile.json

sdk-log.mddocs/

SDK Log Implementation

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.

Package Import

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

Overview

The SDK log package provides:

  1. LoggerProvider: Factory for creating Loggers
  2. Processor: Process log records (SimpleProcessor, BatchProcessor)
  3. Exporter: Export log records to external systems

LoggerProvider

The LoggerProvider is the SDK implementation of the log.LoggerProvider interface.

Type Definition

type LoggerProvider struct {
	// Has unexported fields
}

Creating a LoggerProvider

func NewLoggerProvider(opts ...LoggerProviderOption) *LoggerProvider

Default Configuration:

  • Resource: resource.Default()
  • No Processors (no logs will be exported)
  • AttributeCountLimit: 128
  • AttributeValueLengthLimit: -1 (unlimited)

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...
}

LoggerProvider Methods

// 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) error

LoggerProviderOption

Options 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() LoggerProviderOption

Example:

lp := sdklog.NewLoggerProvider(
	sdklog.WithResource(res),
	sdklog.WithProcessor(processor),
	sdklog.WithAttributeCountLimit(200),
	sdklog.WithAttributeValueLengthLimit(4096),
	sdklog.WithAllowKeyDuplication(),
)

Processors

Processors process log records before they are exported.

Processor Interface

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

BatchProcessor batches log records and exports them in batches.

func NewBatchProcessor(exporter Exporter, opts ...BatchProcessorOption) *BatchProcessor

Default Configuration:

  • MaxQueueSize: 2048
  • ExportTimeout: 30000 ms
  • ExportInterval: 1000 ms
  • ExportMaxBatchSize: 512

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
}

BatchProcessorOption

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) BatchProcessorOption

SimpleProcessor

SimpleProcessor exports log records synchronously when they are emitted. Not recommended for production use.

func NewSimpleProcessor(exporter Exporter, opts ...SimpleProcessorOption) *SimpleProcessor

Example:

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
}

SimpleProcessorOption

Options for configuring a SimpleProcessor.

type SimpleProcessorOption interface {
	// Has unexported methods
}

FilterProcessor Interface

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 threshold

EnabledParameters

EnabledParameters 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

Exporters send log records to external systems.

Exporter Interface

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 Type

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
}

Complete Example

Full Setup with BatchProcessor

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)
}

Environment Variables

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

Best Practices

1. Use BatchProcessor for Production

// Good: Use batch processor
processor := sdklog.NewBatchProcessor(exporter)

// Bad: Don't use simple processor in production
processor := sdklog.NewSimpleProcessor(exporter) // Synchronous, slow

2. Always Shutdown LoggerProvider

lp := 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)
	}
}()

3. Include Trace Context

// 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())
}

4. Configure Appropriate Limits

lp := sdklog.NewLoggerProvider(
	sdklog.WithResource(res),
	sdklog.WithProcessor(processor),
	// Limits are configured via environment variables or code
)

Related Documentation

  • Logging API: Core logging API interfaces
  • SDK Resource: Resource detection and configuration
  • OTLP Exporters: OTLP log exporters
  • Other Exporters: Stdout and other exporters