Documentation
¶
Overview ¶
Package logger provides a production-grade structured logging system built on zap. It supports custom formatting, distributed tracing, and observability integration.
Package logger provides common types and constants for structured logging.
Index ¶
- func IsMetadataField(key string) bool
- func NewCallerHook(core zapcore.Core, level zapcore.Level) zapcore.Core
- func NewJSONEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder
- func NewTextEncoder(cfg zapcore.EncoderConfig, enableColor bool, level zapcore.Level) zapcore.Encoder
- type CallerHook
- type ColorCode
- type Config
- type ContextKey
- type FakeLogger
- func (f *FakeLogger) Debug(msg string, fields ...zap.Field)
- func (f *FakeLogger) Error(msg string, fields ...zap.Field)
- func (f *FakeLogger) Fatal(msg string, fields ...zap.Field)
- func (f *FakeLogger) Info(msg string, fields ...zap.Field)
- func (f *FakeLogger) Named(name string) *FakeLogger
- func (f *FakeLogger) Sync() error
- func (f *FakeLogger) Warn(msg string, fields ...zap.Field)
- func (f *FakeLogger) With(fields ...zap.Field) *FakeLogger
- type LogFormat
- type LogLevel
- type Logger
- func (l *Logger) Debug(msg string, fields ...zap.Field)
- func (l *Logger) Error(msg string, fields ...zap.Field)
- func (l *Logger) Fatal(msg string, fields ...zap.Field)
- func (l *Logger) Info(msg string, fields ...zap.Field)
- func (l *Logger) Named(name string) *Logger
- func (l *Logger) Sugar() *zap.SugaredLogger
- func (l *Logger) Sync() error
- func (l *Logger) Warn(msg string, fields ...zap.Field)
- func (l *Logger) With(fields ...zap.Field) *Logger
- func (l *Logger) Zap() *zap.Logger
- type MetadataField
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsMetadataField ¶
IsMetadataField checks if a field key is a metadata field.
func NewCallerHook ¶
NewCallerHook creates a Core wrapper that injects caller info based on verbosity. The level parameter should be the logger's configured level (not individual entry level).
func NewJSONEncoder ¶
func NewJSONEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder
NewJSONEncoder creates an encoder for structured JSON output. Each log entry is a single-line JSON object.
func NewTextEncoder ¶
func NewTextEncoder(cfg zapcore.EncoderConfig, enableColor bool, level zapcore.Level) zapcore.Encoder
NewTextEncoder creates an encoder for human-readable text output. enableColor determines whether ANSI color codes are added to level brackets.
Types ¶
type CallerHook ¶
CallerHook wraps zapcore.Core to inject caller information based on log level.
Verbosity rules (progressive disclosure):
- DEBUG level: ALL logs include trace_id + caller + function + line
- INFO level: clean output, no extra fields
- WARN level: clean output, no extra fields (same as info)
- ERROR level: adds caller only
This follows the best practice of wrapping Core instead of Encoder.
type ColorCode ¶
type ColorCode string
ColorCode represents ANSI color escape sequences for terminal output.
func ColorForLevel ¶
ColorForLevel returns the appropriate ANSI color code for a log level.
type Config ¶
type Config struct {
// Level controls minimum log level: "debug", "info", "warn", "error"
Level string
// Format controls output format: "text" (human-readable), "json" (structured)
// Default is "json" for k8s log collection compatibility
Format string
// Writer is the output destination (default: os.Stdout)
// Can be wrapped with async/metrics writers for observability
Writer io.Writer
}
Config holds logger configuration parameters. This is a value type (small, immutable struct passed by value).
type ContextKey ¶
type ContextKey string
ContextKey is a typed key for context values to prevent collisions.
const ( // TraceIDKey is the context key for storing trace IDs. TraceIDKey ContextKey = "trace_id" // LoggerKey is the context key for storing logger instances. LoggerKey ContextKey = "logger" )
func (ContextKey) String ¶
func (k ContextKey) String() string
String returns the context key as a string.
type FakeLogger ¶
type FakeLogger struct{}
FakeLogger is a no-op logger implementation for testing. All methods are no-ops and do not produce output. This is useful in unit tests to avoid log noise.
func NewFakeLogger ¶
func NewFakeLogger() *FakeLogger
NewFakeLogger creates a new FakeLogger instance.
Example ¶
ExampleNewFakeLogger demonstrates using FakeLogger for tests.
package main
import (
"github.com/grhili/cd-operator/pkg/logger"
)
func main() {
// Use FakeLogger in tests to avoid log noise
fake := logger.NewFakeLogger()
// All methods are no-ops
fake.Info("this will not produce output")
fake.Error("this will not produce output")
fake.Sync() // Safe to call
}
Output:
func (*FakeLogger) Debug ¶
func (f *FakeLogger) Debug(msg string, fields ...zap.Field)
Debug is a no-op implementation for testing that discards all debug log output.
func (*FakeLogger) Error ¶
func (f *FakeLogger) Error(msg string, fields ...zap.Field)
Error is a no-op implementation for testing that discards all error log output.
func (*FakeLogger) Fatal ¶
func (f *FakeLogger) Fatal(msg string, fields ...zap.Field)
Fatal is a no-op implementation for testing that discards the message and does not exit the process.
func (*FakeLogger) Info ¶
func (f *FakeLogger) Info(msg string, fields ...zap.Field)
Info is a no-op implementation for testing that discards all info log output.
func (*FakeLogger) Named ¶
func (f *FakeLogger) Named(name string) *FakeLogger
Named returns the same FakeLogger (no-op).
func (*FakeLogger) Warn ¶
func (f *FakeLogger) Warn(msg string, fields ...zap.Field)
Warn is a no-op implementation for testing that discards all warning log output.
func (*FakeLogger) With ¶
func (f *FakeLogger) With(fields ...zap.Field) *FakeLogger
With returns the same FakeLogger (no-op).
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger wraps zap.Logger with custom configuration and observability hooks. This is a pointer type (holds state, manages zap instance lifecycle).
func New ¶
New creates a new Logger from the given configuration. Uses zap.Config + Build() pattern for proper initialization. Returns error if configuration is invalid.
Example:
log, err := logger.New(logger.Config{
Level: "debug",
Format: "json",
Writer: os.Stdout,
})
if err != nil {
return err
}
defer log.Sync() // CRITICAL: flush buffered logs
Example ¶
ExampleNew demonstrates basic logger creation and usage.
package main
import (
"os"
"github.com/grhili/cd-operator/pkg/logger"
"go.uber.org/zap"
)
func main() {
// Create logger with JSON format (default for k8s)
log, err := logger.New(logger.Config{
Level: "info",
Format: "json",
Writer: os.Stdout,
})
if err != nil {
panic(err)
}
defer log.Sync()
// Basic logging
log.Info("application started", zap.String("service", "cd-operator"))
}
Output:
Example (TextFormat) ¶
ExampleNew_textFormat demonstrates logger with human-readable text format.
package main
import (
"os"
"github.com/grhili/cd-operator/pkg/logger"
"go.uber.org/zap"
)
func main() {
// Create logger with text format for local development
log, err := logger.New(logger.Config{
Level: "debug",
Format: "text",
Writer: os.Stdout,
})
if err != nil {
panic(err)
}
defer log.Sync()
// Debug logging
log.Debug("processing request", zap.String("path", "/api/v1/health"))
}
Output:
func (*Logger) Debug ¶
Debug logs a debug-level message with typed fields. Only appears when log level is set to "debug".
func (*Logger) Error ¶
Error logs an error-level message with typed fields. Always use zap.Error() field for actual error values.
Example ¶
ExampleLogger_Error demonstrates error logging with context.
package main
import (
"os"
"github.com/grhili/cd-operator/pkg/logger"
"go.uber.org/zap"
)
func main() {
log, err := logger.New(logger.Config{
Level: "info",
Format: "text",
Writer: os.Stdout,
})
if err != nil {
panic(err)
}
defer log.Sync()
// Error logging includes caller information automatically
log.Error("failed to sync application",
zap.String("app", "my-app"),
zap.String("namespace", "default"),
zap.Error(err),
)
}
Output:
func (*Logger) Fatal ¶
Fatal logs a fatal-level message and exits with os.Exit(1). Use sparingly - only for unrecoverable errors.
func (*Logger) Info ¶
Info logs an info-level message with typed fields. This is the default log level for production.
func (*Logger) Named ¶
Named creates a child logger with the given name. Use this to identify subsystems/components in logs. Returns a new Logger instance (doesn't modify the parent).
Example:
ghLogger := baseLogger.Named("github")
ghLogger.Info("api call") // logs with {"logger":"github"}
Example ¶
ExampleLogger_Named demonstrates creating named loggers for subsystems.
package main
import (
"os"
"github.com/grhili/cd-operator/pkg/logger"
)
func main() {
log, err := logger.New(logger.Config{
Level: "info",
Format: "json",
Writer: os.Stdout,
})
if err != nil {
panic(err)
}
defer log.Sync()
// Create named loggers for different subsystems
ghLogger := log.Named("github")
argoLogger := log.Named("argocd")
ghLogger.Info("fetching repository")
argoLogger.Info("syncing application")
}
Output:
func (*Logger) Sugar ¶
func (l *Logger) Sugar() *zap.SugaredLogger
Sugar returns a zap.SugaredLogger for use with APIs that need key-value logging. The sugared logger is slower but more convenient for variadic key-value pairs.
Example:
sugar := log.Sugar()
sugar.Infow("request processed", "method", "GET", "path", "/api/data")
func (*Logger) Sync ¶
Sync flushes any buffered log entries. CRITICAL: Always defer this after creating a logger. Failing to call Sync() may result in lost logs.
func (*Logger) Warn ¶
Warn logs a warning-level message with typed fields. Use for recoverable errors or unexpected conditions.
func (*Logger) With ¶
With creates a child logger with the given fields attached. Use this for stable metadata that should appear in all subsequent logs. Returns a new Logger instance (doesn't modify the parent).
Example:
baseLogger := logger.New(cfg).With(
zap.String("service", "cd-operator"),
zap.String("version", "v1.0.0"),
)
Example ¶
ExampleLogger_With demonstrates creating child loggers with context.
package main
import (
"os"
"github.com/grhili/cd-operator/pkg/logger"
"go.uber.org/zap"
)
func main() {
log, err := logger.New(logger.Config{
Level: "info",
Format: "json",
Writer: os.Stdout,
})
if err != nil {
panic(err)
}
defer log.Sync()
// Create child logger with service metadata
serviceLog := log.With(
zap.String("service", "cd-operator"),
zap.String("version", "v1.0.0"),
)
// All logs from serviceLog will include service and version fields
serviceLog.Info("service initialized")
serviceLog.Info("processing webhook")
}
Output:
type MetadataField ¶
type MetadataField string
MetadataField represents field keys that are considered metadata (not per-log data) and subject to progressive disclosure filtering.
const ( FieldService MetadataField = "service" FieldVersion MetadataField = "version" FieldTraceID MetadataField = "trace_id" FieldLogger MetadataField = "logger" FieldCaller MetadataField = "caller" FieldFunction MetadataField = "function" FieldLine MetadataField = "line" )