Documentation
¶
Overview ¶
Package olog provides OpenTelemetry Ergonomic Logs API.
This package addresses the usability concerns with the OpenTelemetry Logs API by providing a user-friendly frontend interface while using the OpenTelemetry Logs API as the backend. It offers simple methods similar to popular logging libraries while maintaining full compatibility with OpenTelemetry's structured logging capabilities.
Basic Usage ¶
The simplest way to use olog is by creating a logger instance:
import (
"context"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
ctx := context.Background()
logger := olog.New(olog.Options{
Provider: global.GetLoggerProvider(),
Name: "myapp",
})
logger.InfoAttr(ctx, "application.started",
log.String("version", "1.0.0"),
log.Int("port", 8080))
logger.WarnAttr(ctx, "deprecated.feature.used", log.String("feature", "old-api"))
logger.ErrorAttr(ctx, "connection.failed", log.String("host", "db.example.com"))
logger.DebugAttr(ctx, "request.processing",
log.String("method", "GET"),
log.String("path", "/api/users"))
// Check if logging is enabled before expensive operations
if logger.DebugEnabled(ctx, "debug.info") {
expensiveData := computeExpensiveDebugInfo()
logger.DebugAttr(ctx, "debug.info", log.String("data", expensiveData))
}
Logger Composition ¶
Use WithAttr to create loggers with common attributes:
serviceLogger := logger.WithAttr(
log.String("service", "user-service"),
log.String("version", "2.1.0"))
serviceLogger.InfoAttr(ctx, "user.created", log.Int("user_id", 12345))
requestLogger := serviceLogger.WithAttr(log.String("request_id", "req-789"))
requestLogger.InfoAttr(ctx, "request.processing", log.String("endpoint", "/api/users"))
Use structured attributes to organize your logs:
httpLogger := logger.WithAttr(log.String("component", "http"))
httpLogger.InfoAttr(ctx, "http.request",
log.String("method", "POST"),
log.Int("status", 201))
// Logs with component="http" and the specified attributes
Event Logging ¶
Log structured events at different severity levels following semantic conventions:
// Log events at different levels
logger.InfoAttr(ctx, "user.login",
log.String("user.id", "12345"),
log.String("user.email", "user@example.com"),
log.String("session.id", "sess-abc123"))
logger.WarnAttr(ctx, "rate.limit.exceeded",
log.String("client.ip", "192.168.1.100"),
log.Int("requests_per_minute", 150))
API Variants ¶
olog provides two variants for emitting logs and events:
- Variadic methods (Trace, Debug, Info, Warn, Error, Log) accept alternating key-value pairs as interface{} arguments for convenience
- Attr methods (TraceAttr, DebugAttr, InfoAttr, WarnAttr, ErrorAttr, LogAttr) accept typed log.KeyValue attributes
The Attr variants are recommended for production use as they provide:
Better performance: no reflection or runtime type conversion overhead
Type safety: compile-time validation of attribute types
Better IDE support: autocompletion and type checking
// Variadic - convenient but less performant logger.Info(ctx, "user.created", "user_id", 12345, "email", "user@example.com")
// Attr - more performant and type-safe logger.InfoAttr(ctx, "user.created", log.Int("user_id", 12345), log.String("email", "user@example.com"))
Performance ¶
olog is designed with performance in mind:
- Use TraceEnabled, DebugEnabled, InfoEnabled, WarnEnabled, ErrorEnabled checks to avoid expensive operations when logging is disabled
- Logger composition with WithAttr pre-processes common attributes
- Direct integration with OpenTelemetry Logs API avoids unnecessary conversions
- Prefer Attr variants (TraceAttr, InfoAttr, etc.) over variadic methods for better performance and type safety
Design Goals ¶
This package is designed to provide:
- Simple, ergonomic API similar to popular logging libraries
- Performance-oriented design with efficient enabled checks
- Event logging capabilities for OpenTelemetry semantic events
- Support for structured logging with key-value pairs
- Logger composition for better code organization and performance
Index ¶
- type Logger
- func (l *Logger) Debug(ctx context.Context, eventName string, args ...any)
- func (l *Logger) DebugAttr(ctx context.Context, eventName string, attrs ...log.KeyValue)
- func (l *Logger) DebugEnabled(ctx context.Context, eventName string) bool
- func (l *Logger) Error(ctx context.Context, eventName string, args ...any)
- func (l *Logger) ErrorAttr(ctx context.Context, eventName string, attrs ...log.KeyValue)
- func (l *Logger) ErrorEnabled(ctx context.Context, eventName string) bool
- func (l *Logger) Info(ctx context.Context, eventName string, args ...any)
- func (l *Logger) InfoAttr(ctx context.Context, eventName string, attrs ...log.KeyValue)
- func (l *Logger) InfoEnabled(ctx context.Context, eventName string) bool
- func (l *Logger) Log(ctx context.Context, level log.Severity, eventName string, args ...any)
- func (l *Logger) LogAttr(ctx context.Context, level log.Severity, eventName string, ...)
- func (l *Logger) Trace(ctx context.Context, eventName string, args ...any)
- func (l *Logger) TraceAttr(ctx context.Context, eventName string, attrs ...log.KeyValue)
- func (l *Logger) TraceEnabled(ctx context.Context, eventName string) bool
- func (l *Logger) Warn(ctx context.Context, eventName string, args ...any)
- func (l *Logger) WarnAttr(ctx context.Context, eventName string, attrs ...log.KeyValue)
- func (l *Logger) WarnEnabled(ctx context.Context, eventName string) bool
- func (l *Logger) With(args ...any) *Logger
- func (l *Logger) WithAttr(attrs ...log.KeyValue) *Logger
- type Options
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Logger ¶
Logger provides an ergonomic frontend API for OpenTelemetry structured logging. It provides convenience methods for event logging patterns while using the OpenTelemetry Logs API as the backend.
The Logger offers two styles of API:
- Argument-based methods (Trace, Debug, Info, Warn, Error, Log, With) that accept alternating key-value pairs as ...any arguments
- Attribute-based methods (TraceAttr, DebugAttr, InfoAttr, WarnAttr, ErrorAttr, LogAttr, WithAttr) that accept strongly-typed log.KeyValue attributes
The attribute-based methods provide better type safety and can offer better performance in some scenarios, particularly when used with WithAttr for pre-configured loggers.
Example ¶
package main
import (
"context"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a logger for events
logger := olog.New(olog.Options{Provider: global.GetLoggerProvider(), Name: "example"})
// Log structured events at different severity levels
logger.Info(ctx, "user.login",
"user.id", "12345",
"user.email", "user@example.com",
"session.id", "sess-abc123",
"client.ip", "192.168.1.100")
logger.Warn(ctx, "rate.limit.approached",
"client.ip", "192.168.1.100",
"requests_per_minute", 85,
"limit", 100)
logger.Error(ctx, "payment.failed",
"payment.id", "pay-xyz789",
"payment.amount", 99.99,
"payment.currency", "USD",
"user.id", "12345",
"error", "insufficient_funds")
// Check if debug event logging is enabled before expensive operations
if logger.DebugEnabled(ctx, "debug.session.details") {
logger.Debug(ctx, "debug.session.details",
"session.data", computeSessionDebugInfo(),
"trace.id", "trace-abc123")
}
}
func computeSessionDebugInfo() string {
return "session debug information"
}
Output:
Example (WithAttr) ¶
package main
import (
"context"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a base logger
baseLogger := olog.New(olog.Options{Provider: global.GetLoggerProvider(), Name: "example"})
// Create a logger with common attributes using WithAttr
serviceLogger := baseLogger.WithAttr(
log.String("service.name", "user-service"),
log.String("service.version", "2.1.0"),
log.String("deployment.environment", "production"))
// All subsequent events will include the service attributes
serviceLogger.InfoAttr(ctx, "service.started",
log.Int64("port", 8080),
log.String("build", "abc1234"))
// Chain additional attributes for request-scoped logging
requestLogger := serviceLogger.WithAttr(
log.String("request.id", "req-789"),
log.String("user.id", "user-456"))
requestLogger.InfoAttr(ctx, "request.processing",
log.String("http.method", "POST"),
log.String("http.route", "/api/users"))
requestLogger.ErrorAttr(ctx, "validation.failed",
log.String("field", "email"),
log.String("error", "invalid format"))
// Mix WithAttr and With methods
mixedLogger := requestLogger.With("trace.id", "trace-xyz").WithAttr(log.Bool("debug.enabled", true))
mixedLogger.DebugAttr(ctx, "processing.detail",
log.Int64("processing.step", 3),
log.Float64("processing.duration_ms", 12.5))
}
Output:
func New ¶
New creates a new Logger with the provided options. If options.Provider is nil, the global LoggerProvider is used. If options.Name is empty, the caller's full package name is automatically detected.
Example (Minimal) ¶
package main
import (
"context"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Minimal configuration.
// The logger name is the caller's full package name.
logger := olog.New(olog.Options{})
logger.Info(ctx, "minimal.example")
}
Output:
Example (WithGlobalProvider) ¶
package main
import (
"context"
"go.opentelemetry.io/otel/attribute"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a logger that uses the global provider (provider is nil)
logger := olog.New(olog.Options{
Name: "global-logger",
Attributes: attribute.NewSet(
attribute.String("component", "authentication"),
attribute.String("version", "2.0.0"),
),
})
logger.Info(ctx, "logger.initialized", "uses_global_provider", true)
}
Output:
Example (WithOptions) ¶
package main
import (
"context"
"go.opentelemetry.io/otel/attribute"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a logger using the new Options API
logger := olog.New(olog.Options{
Name: "my-service",
Version: "1.2.3",
Attributes: attribute.NewSet(
attribute.String("service.name", "user-service"),
attribute.String("deployment.environment", "production"),
attribute.Int("service.port", 8080),
),
})
// All event records will include the pre-configured attributes
logger.Info(ctx, "service.started", "status", "ready")
logger.Warn(ctx, "resource.high_usage", "memory_percent", 85.5)
logger.Error(ctx, "database.connection_failed", "retry_count", 3)
}
Output:
func (*Logger) Debug ¶
Debug logs a debug-level event with the specified name and optional key-value pairs.
func (*Logger) DebugAttr ¶
DebugAttr logs a debug-level event with the specified name and the provided attributes.
func (*Logger) DebugEnabled ¶
DebugEnabled reports whether the logger emits debug-level event log records for the specified event name.
func (*Logger) Error ¶
Error logs an error-level event with the specified name and optional key-value pairs.
func (*Logger) ErrorAttr ¶
ErrorAttr logs an error-level event with the specified name and the provided attributes.
func (*Logger) ErrorEnabled ¶
ErrorEnabled reports whether the logger emits error-level event log records for the specified event name.
func (*Logger) Info ¶
Info logs an info-level event with the specified name and optional key-value pairs.
func (*Logger) InfoAttr ¶
InfoAttr logs an info-level event with the specified name and the provided attributes.
Example ¶
package main
import (
"context"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a logger for structured events
logger := olog.New(olog.Options{Provider: global.GetLoggerProvider(), Name: "example"})
// Log events at different severity levels using the attribute-based methods
logger.InfoAttr(ctx, "user.signup",
log.String("user.id", "user-789"),
log.String("user.email", "newuser@example.com"),
log.String("signup.method", "email"),
log.Bool("email.verified", false))
logger.WarnAttr(ctx, "api.deprecated.usage",
log.String("api.endpoint", "/v1/users"),
log.String("client.id", "client-123"),
log.String("replacement", "/v2/users"))
logger.ErrorAttr(ctx, "payment.failed",
log.String("payment.id", "pay-abc123"),
log.Float64("payment.amount", 49.99),
log.String("payment.currency", "USD"),
log.String("payment.method", "credit_card"),
log.String("error.code", "card_declined"))
logger.DebugAttr(ctx, "file.uploaded",
log.String("file.id", "file-456"),
log.String("file.name", "document.pdf"),
log.Int64("file.size_bytes", 2048576),
log.String("user.id", "user-123"))
}
Output:
func (*Logger) InfoEnabled ¶
InfoEnabled reports whether the logger emits info-level event log records for the specified event name.
func (*Logger) Log ¶
Log logs an event at the specified level with the specified name and optional key-value pairs.
func (*Logger) LogAttr ¶
func (l *Logger) LogAttr(ctx context.Context, level log.Severity, eventName string, attrs ...log.KeyValue)
LogAttr logs an event at the specified level with the specified name and the provided attributes.
func (*Logger) Trace ¶
Trace logs a trace-level event with the specified name and optional key-value pairs.
func (*Logger) TraceAttr ¶
TraceAttr logs a trace-level event with the specified name and the provided attributes.
func (*Logger) TraceEnabled ¶
TraceEnabled reports whether the logger emits trace-level event log records for the specified event name.
func (*Logger) Warn ¶
Warn logs a warn-level event with the specified name and optional key-value pairs.
func (*Logger) WarnAttr ¶
WarnAttr logs a warn-level event with the specified name and the provided attributes.
func (*Logger) WarnEnabled ¶
WarnEnabled reports whether the logger emits warn-level event log records for the specified event name.
func (*Logger) With ¶
With returns a new Logger that includes the given attributes in all log records.
Example ¶
package main
import (
"context"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a base logger
logger := olog.New(olog.Options{Provider: global.GetLoggerProvider(), Name: "example"})
// Pre-configure logger with common attributes for better performance
requestLogger := logger.With(
"service", "api-server",
"version", "1.2.3",
"request_id", generateRequestID(),
)
// Use the pre-configured logger for all request-scoped events
requestLogger.Info(ctx, "request.started", "method", "GET", "path", "/api/users")
requestLogger.Info(ctx, "database.query", "table", "users", "duration_ms", 23)
requestLogger.Info(ctx, "request.completed", "status", 200, "total_duration_ms", 145)
}
func generateRequestID() string {
return "req-12345"
}
Output:
type Options ¶
type Options struct {
// Provider is the LoggerProvider to use. If nil, the global LoggerProvider is used.
Provider log.LoggerProvider
// Name is the name of the logger, typically the package or component name.
// If empty, the caller's full package name is automatically detected.
Name string
// Version is the version of the logger, typically the package or component version.
Version string
// Attributes are pre-configured attributes that will be included in all log records.
Attributes attribute.Set
}
Options contains configuration options for creating a Logger.