Documentation
¶
Overview ¶
Package olog provides an ergonomic OpenTelemetry Logging Facade.
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.TraceAttr(ctx, "detailed tracing", log.String("trace_id", "abc123"))
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, "failed to connect", log.String("host", "db.example.com"))
logger.DebugAttr(ctx, "processing request",
log.String("method", "GET"),
log.String("path", "/api/users"))
// Check if logging is enabled before expensive operations
if logger.DebugEnabled(ctx) {
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, "processing request", log.String("endpoint", "/api/users"))
Use structured attributes to organize your logs:
httpLogger := logger.WithAttr(log.String("component", "http"))
httpLogger.InfoAttr(ctx, "request",
log.String("method", "POST"),
log.Int("status", 201))
// Logs with component="http" and the specified attributes
Event Logging ¶
Log structured events following semantic conventions:
logger.EventAttr(ctx, "user.login",
log.String("user.id", "12345"),
log.String("user.email", "user@example.com"),
log.String("session.id", "sess-abc123"))
Performance ¶
olog is designed with performance in mind:
- Use TraceEnabled, DebugEnabled, InfoEnabled, WarnEnabled, and 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
Design Goals ¶
This package is designed to provide:
- Simple, ergonomic API similar to popular logging libraries
- Performance-oriented design with efficient enabled checks
- Full compatibility with OpenTelemetry Logs API and ecosystem
- Support for structured logging with key-value pairs
- Logger composition for better code organization and performance
- Event logging capabilities for semantic events
Index ¶
- type Logger
- func (l *Logger) Debug(ctx context.Context, msg string, args ...any)
- func (l *Logger) DebugAttr(ctx context.Context, msg string, attrs ...log.KeyValue)
- func (l *Logger) DebugEnabled(ctx context.Context) bool
- func (l *Logger) Error(ctx context.Context, msg string, args ...any)
- func (l *Logger) ErrorAttr(ctx context.Context, msg string, attrs ...log.KeyValue)
- func (l *Logger) ErrorEnabled(ctx context.Context) bool
- func (l *Logger) Event(ctx context.Context, name string, args ...any)
- func (l *Logger) EventAttr(ctx context.Context, name string, attrs ...log.KeyValue)
- func (l *Logger) Info(ctx context.Context, msg string, args ...any)
- func (l *Logger) InfoAttr(ctx context.Context, msg string, attrs ...log.KeyValue)
- func (l *Logger) InfoEnabled(ctx context.Context) bool
- func (l *Logger) Log(ctx context.Context, level log.Severity, msg string, args ...any)
- func (l *Logger) LogAttr(ctx context.Context, level log.Severity, msg string, attrs ...log.KeyValue)
- func (l *Logger) Trace(ctx context.Context, msg string, args ...any)
- func (l *Logger) TraceAttr(ctx context.Context, msg string, attrs ...log.KeyValue)
- func (l *Logger) TraceEnabled(ctx context.Context) bool
- func (l *Logger) Warn(ctx context.Context, msg string, args ...any)
- func (l *Logger) WarnAttr(ctx context.Context, msg string, attrs ...log.KeyValue)
- func (l *Logger) WarnEnabled(ctx context.Context) 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 common 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, Event, With) that accept alternating key-value pairs as ...any arguments
- Attribute-based methods (TraceAttr, DebugAttr, InfoAttr, WarnAttr, ErrorAttr, LogAttr, EventAttr, 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 (Basic) ¶
package main
import (
"context"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a logger instance
logger := olog.New(olog.Options{})
// Use the logger for basic logging
logger.Info(ctx, "application started", "version", "1.0.0", "port", 8080)
logger.Warn(ctx, "deprecated feature used", "feature", "old-api")
logger.Error(ctx, "failed to connect", "host", "db.example.com", "error", "connection timeout")
logger.Debug(ctx, "processing request", "method", "GET", "path", "/api/users")
// Check if logging is enabled before expensive operations
if logger.DebugEnabled(ctx) {
expensiveData := computeExpensiveDebugInfo()
logger.Debug(ctx, "debug info", "data", expensiveData)
}
}
func computeExpensiveDebugInfo() string {
return "expensive debug data"
}
Example (EventAttr) ¶
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 using the attribute-based method for better type safety
logger.EventAttr(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.EventAttr(ctx, "payment.processed",
log.String("payment.id", "pay-abc123"),
log.Float64("payment.amount", 49.99),
log.String("payment.currency", "USD"),
log.String("payment.method", "credit_card"))
logger.EventAttr(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"))
}
Example (Events) ¶
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 following semantic conventions
logger.Event(ctx, "user.login",
"user.id", "12345",
"user.email", "user@example.com",
"session.id", "sess-abc123",
"client.ip", "192.168.1.100")
logger.Event(ctx, "payment.processed",
"payment.id", "pay-xyz789",
"payment.amount", 99.99,
"payment.currency", "USD",
"user.id", "12345")
// Events with additional attributes
logger.Event(ctx, "order.created",
"order.id", "order-456",
"order.total", 149.99,
"customer.id", "cust-789",
"domain", "ecommerce")
}
Example (Performance) ¶
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"})
// Check if logging is enabled to avoid expensive operations
if logger.DebugEnabled(ctx) {
// Only compute expensive debug information if debug logging is enabled
debugData := computeExpensiveDebugInfo()
logger.Debug(ctx, "detailed debug information", "data", debugData)
}
// 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 logging
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 computeExpensiveDebugInfo() string {
return "expensive debug data"
}
func generateRequestID() string {
return "req-12345"
}
Example (With) ¶
package main
import (
"context"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Create a logger and add common attributes
baseLogger := olog.New(olog.Options{Provider: global.GetLoggerProvider(), Name: "example"})
logger := baseLogger.With("service", "user-service", "version", "2.1.0")
// All log records from this logger will include the common attributes
logger.Info(ctx, "user created", "user_id", 12345, "email", "user@example.com")
logger.Warn(ctx, "user login failed", "user_id", 12345, "reason", "invalid password")
// Chain with additional attributes
requestLogger := logger.With("request_id", "req-789", "ip", "192.168.1.100")
requestLogger.Info(ctx, "processing request", "endpoint", "/api/users/12345")
requestLogger.Error(ctx, "request failed", "status", 500, "duration_ms", 1234)
}
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 logs 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, "processing request",
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, "detailed processing info",
log.Int64("processing.step", 3),
log.Float64("processing.duration_ms", 12.5))
}
Example (WithAttributes) ¶
package main
import (
"context"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
"github.com/pellared/olog"
)
func main() {
ctx := context.Background()
// Import the log package for KeyValue construction
// import "go.opentelemetry.io/otel/log"
// Create a logger instance
logger := olog.New(olog.Options{Provider: global.GetLoggerProvider(), Name: "example"})
// Using the new attribute-based methods for type-safe logging
logger.InfoAttr(ctx, "user logged in",
log.String("user.id", "12345"),
log.String("user.email", "user@example.com"),
log.Int64("session.duration", 3600),
log.Bool("first_login", false))
logger.WarnAttr(ctx, "rate limit exceeded",
log.String("client.ip", "192.168.1.100"),
log.Int64("requests_per_minute", 150),
log.Int64("limit", 100))
logger.ErrorAttr(ctx, "database connection failed",
log.String("database.host", "db.example.com"),
log.Int64("database.port", 5432),
log.String("error.type", "connection_timeout"))
// Use LogAttr for custom severity levels
logger.LogAttr(ctx, log.SeverityWarn2, "custom warning",
log.String("component", "cache"),
log.Float64("memory_usage_percent", 85.5))
}
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 - only name is required
logger := olog.New(olog.Options{
Name: "minimal-logger",
})
logger.Info(ctx, "minimal logger example")
}
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, "using global logger provider", "initialized", true)
}
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 log records will include the pre-configured attributes
logger.Info(ctx, "service started", "status", "ready")
logger.Warn(ctx, "high memory usage", "memory_percent", 85.5)
logger.Error(ctx, "database connection failed", "retry_count", 3)
}
func (*Logger) DebugEnabled ¶
DebugEnabled reports whether the logger emits debug-level log records.
func (*Logger) ErrorEnabled ¶
ErrorEnabled reports whether the logger emits error-level log records.
func (*Logger) EventAttr ¶
EventAttr logs an event with the specified name and the provided attributes.
func (*Logger) InfoEnabled ¶
InfoEnabled reports whether the logger emits info-level log records.
func (*Logger) LogAttr ¶
func (l *Logger) LogAttr(ctx context.Context, level log.Severity, msg string, attrs ...log.KeyValue)
LogAttr logs a message at the specified level with the provided attributes.
func (*Logger) TraceEnabled ¶
TraceEnabled reports whether the logger emits trace-level log records.
func (*Logger) WarnEnabled ¶
WarnEnabled reports whether the logger emits warn-level log records.
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.