The Logger type provides fast, leveled, and structured logging designed for contexts where every microsecond and allocation matters. It supports both synchronous and asynchronous writing, zero allocation field logging, and dynamic context extraction.
Creating loggers
New
Constructs a new Logger writing to the provided io.Writer.
func New(w io.Writer) *Logger
The writer to output logs to. If nil, defaults to standard error.
Applies the default Options. This provides a quick way to instantiate a Logger without configuring advanced features.
Example
logger := velo.New(os.Stdout)
logger.Info("application started")
NewWithOptions
Constructs a new Logger using the specified Options.
func NewWithOptions(w io.Writer, o Options) *Logger
The writer to output logs to. If nil, defaults to standard error.
Configuration options for the logger
Provides full control over the Logger’s behavior, including asynchronous writing, formatting, and field extraction. This is the recommended way to instantiate a Logger for production applications.
Example
logger := velo.NewWithOptions(os.Stdout, velo.Options{
Level: velo.InfoLevel,
ReportTimestamp: true,
Formatter: velo.JSONFormatter,
Async: true,
})
Default
Returns the global default Logger instance.
Initializes a new Logger writing to standard error with timestamp reporting enabled if one does not already exist. Use this for simple applications or quick debugging where dependency injection is unnecessary.
Example
velo.Default().Info("using default logger")
SetDefault
Replaces the global default Logger with the provided instance.
func SetDefault(logger *Logger)
The logger instance to set as the global default
Safely swaps the underlying pointer and closes the previous Logger if one existed. Use this during application startup to configure the global logging behavior.
Example
customLogger := velo.NewWithOptions(os.Stdout, velo.Options{
Formatter: velo.JSONFormatter,
})
velo.SetDefault(customLogger)
Logging methods
Log
Writes a message with loosely typed key-value pairs at the specified level.
func (l *Logger) Log(level Level, msg string, keyvals ...any)
Loosely typed key-value pairs
Performance Note: This method iterates over the key-value pairs to check for errors and capture stack traces. For absolute maximum performance and zero allocations, use the strongly typed LogFields method instead.
Example
logger.Log(velo.InfoLevel, "user logged in", "user_id", 123, "ip", "192.168.1.1")
LogFields
Writes a message with strongly typed fields at the specified level.
func (l *Logger) LogFields(level Level, msg string, fields ...Field)
Guarantees zero allocations on the hot path, making it ideal for extreme high throughput, latency critical applications.
Example
logger.LogFields(velo.InfoLevel, "user logged in",
velo.Int("user_id", 123),
velo.String("ip", "192.168.1.1"),
)
LogContext
Writes a message with loosely typed key-value pairs at the specified level, extracting context-specific fields.
func (l *Logger) LogContext(ctx context.Context, level Level, msg string, keyvals ...any)
The context to extract fields from
Loosely typed key-value pairs
Extracts context-specific fields if a ContextExtractor is configured.
Example
ctx := context.WithValue(context.Background(), "request_id", "abc123")
logger.LogContext(ctx, velo.InfoLevel, "processing request", "status", "started")
LogContextFields
Writes a message with strongly typed fields at the specified level, extracting context-specific fields.
func (l *Logger) LogContextFields(ctx context.Context, level Level, msg string, fields ...Field)
The context to extract fields from
Guarantees zero allocations on the hot path.
Example
ctx := context.WithValue(context.Background(), "request_id", "abc123")
logger.LogContextFields(ctx, velo.InfoLevel, "processing request",
velo.String("status", "started"),
)
Logf
Formats and writes a message at the specified level.
func (l *Logger) Logf(level Level, format string, args ...any)
Uses fmt.Sprintf to construct the message. This incurs allocation and formatting overhead. Avoid using this in performance critical paths.
Example
logger.Logf(velo.InfoLevel, "user %d logged in from %s", 123, "192.168.1.1")
Level-specific methods
Debug
Writes a message at DebugLevel with loosely typed key-value pairs.
func (l *Logger) Debug(msg string, keyvals ...any)
Example
logger.Debug("variable state", "x", 10, "y", 20)
Info
Writes a message at InfoLevel with loosely typed key-value pairs.
func (l *Logger) Info(msg string, keyvals ...any)
Example
logger.Info("server started", "port", 8080)
Warn
Writes a message at WarnLevel with loosely typed key-value pairs.
func (l *Logger) Warn(msg string, keyvals ...any)
Example
logger.Warn("high memory usage", "percent", 85)
Error
Writes a message at ErrorLevel with loosely typed key-value pairs.
func (l *Logger) Error(msg string, keyvals ...any)
Example
logger.Error("failed to connect", "error", err, "retries", 3)
Panic
Writes a message at PanicLevel with loosely typed key-value pairs, then panics.
func (l *Logger) Panic(msg string, keyvals ...any)
Example
logger.Panic("critical failure", "component", "database")
Fatal
Writes a message at FatalLevel with loosely typed key-value pairs, then calls os.Exit(1).
func (l *Logger) Fatal(msg string, keyvals ...any)
Example
logger.Fatal("cannot recover", "error", err)
Print
Writes a message with no level and loosely typed key-value pairs.
func (l *Logger) Print(msg string, keyvals ...any)
Example
logger.Print("general output", "status", "ok")
Debugf
Formats and writes a message at DebugLevel.
func (l *Logger) Debugf(format string, args ...any)
Infof
Formats and writes a message at InfoLevel.
func (l *Logger) Infof(format string, args ...any)
Warnf
Formats and writes a message at WarnLevel.
func (l *Logger) Warnf(format string, args ...any)
Errorf
Formats and writes a message at ErrorLevel.
func (l *Logger) Errorf(format string, args ...any)
Panicf
Formats and writes a message at PanicLevel, then panics.
func (l *Logger) Panicf(format string, args ...any)
Fatalf
Formats and writes a message at FatalLevel, then calls os.Exit(1).
func (l *Logger) Fatalf(format string, args ...any)
Printf
Formats and writes a message with no level.
func (l *Logger) Printf(format string, args ...any)
Strongly typed field methods
DebugFields
Writes a message at DebugLevel with strongly typed fields, guaranteeing zero allocations.
func (l *Logger) DebugFields(msg string, fields ...Field)
Example
logger.DebugFields("state", velo.Int("x", 10), velo.Int("y", 20))
InfoFields
Writes a message at InfoLevel with strongly typed fields, guaranteeing zero allocations.
func (l *Logger) InfoFields(msg string, fields ...Field)
Example
logger.InfoFields("request completed", velo.Int("duration_ms", 42))
WarnFields
Writes a message at WarnLevel with strongly typed fields, guaranteeing zero allocations.
func (l *Logger) WarnFields(msg string, fields ...Field)
ErrorFields
Writes a message at ErrorLevel with strongly typed fields, guaranteeing zero allocations.
func (l *Logger) ErrorFields(msg string, fields ...Field)
Example
logger.ErrorFields("connection failed", velo.Err(err), velo.Int("retry", 3))
PanicFields
Writes a message at PanicLevel with strongly typed fields, guaranteeing zero allocations, then panics.
func (l *Logger) PanicFields(msg string, fields ...Field)
FatalFields
Writes a message at FatalLevel with strongly typed fields, guaranteeing zero allocations, then calls os.Exit(1).
func (l *Logger) FatalFields(msg string, fields ...Field)
Creating child loggers
With
Creates a child Logger that includes the provided loosely typed key-value pairs.
func (l *Logger) With(keyvals ...any) *Logger
Loosely typed key-value pairs to attach to the child logger
Copies the parent’s configuration and appends the new fields. If the JSONFormatter is active, it encodes the fields early to avoid redundant serialization on every log call. Use this to attach contextual data to a Logger for a specific scope or request.
Example
requestLogger := logger.With("request_id", "abc123", "user_id", 456)
requestLogger.Info("processing request")
WithFields
Creates a child Logger that includes the provided strongly typed fields.
func (l *Logger) WithFields(fields ...Field) *Logger
Strongly typed fields to attach to the child logger
Provides the highest performance when attaching contextual data to a Logger.
Example
requestLogger := logger.WithFields(
velo.String("request_id", "abc123"),
velo.Int("user_id", 456),
)
requestLogger.Info("processing request")
WithPrefix
Creates a child Logger that prepends the specified prefix to all messages.
func (l *Logger) WithPrefix(prefix string) *Logger
The prefix to prepend to all messages
Use this to visually group logs from a specific component or subsystem.
Example
authLogger := logger.WithPrefix("[AUTH]")
authLogger.Info("user authenticated")
// Output: [AUTH] user authenticated
Configuration methods
SetLevel
Changes the minimum logging level for this Logger dynamically.
func (l *Logger) SetLevel(level Level)
The new minimum logging level
Uses atomic operations to ensure thread safety. The Logger discards any messages below this level. Use this to adjust verbosity at runtime without restarting the application.
Example
logger.SetLevel(velo.DebugLevel)
SetReportTimestamp
Toggles the inclusion of timestamps in log entries.
func (l *Logger) SetReportTimestamp(report bool)
Whether to include timestamps
Disabling timestamps can slightly improve performance and reduce log volume if your log aggregator already assigns timestamps.
Example
logger.SetReportTimestamp(true)
SetReportCaller
Toggles the inclusion of the caller’s file and line number.
func (l *Logger) SetReportCaller(report bool)
Whether to include caller information
Performance Note: Enabling this feature incurs a significant performance penalty because it requires unwinding the stack using runtime.Caller. Use with caution in high throughput, latency critical paths.
Example
logger.SetReportCaller(true)
SetReportStacktrace
Toggles the automatic capture of stack traces for errors.
func (l *Logger) SetReportStacktrace(report bool)
Whether to capture stack traces
When enabled, the Logger captures a stack trace whenever it writes an entry at ErrorLevel or higher, or when an error field is present.
Performance Note: Capturing stack traces incurs a significant performance penalty. Use this feature primarily for debugging or in environments where error rates are low.
Example
logger.SetReportStacktrace(true)
SetPrefix
Changes the prefix prepended to all messages for this Logger.
func (l *Logger) SetPrefix(prefix string)
Use this to dynamically label logs from a specific component.
Example
logger.SetPrefix("[API]")
Changes the timestamp format string.
func (l *Logger) SetTimeFormat(format string)
The new time format string
The format string must conform to the layout expected by the standard time package.
Example
logger.SetTimeFormat("2006-01-02T15:04:05.000Z07:00")
SetTimeFunction
Changes the function used to generate timestamps.
func (l *Logger) SetTimeFunction(f TimeFunction)
Use this to inject a custom clock for testing or to apply specific timezone adjustments.
Example
logger.SetTimeFunction(func(t time.Time) time.Time {
return t.UTC()
})
Changes the Formatter used to serialize log entries.
func (l *Logger) SetFormatter(f Formatter)
You can switch between built in formatters like JSONFormatter and TextFormatter, or provide a custom implementation.
Example
logger.SetFormatter(velo.JSONFormatter)
Changes the function used to format caller location data.
func (l *Logger) SetCallerFormatter(f CallerFormatter)
The new caller formatter function
Use this to customize how file paths and line numbers appear in your logs.
Example
logger.SetCallerFormatter(velo.LongCallerFormatter)
SetCallerOffset
Changes the number of stack frames to skip when identifying the caller.
func (l *Logger) SetCallerOffset(offset int)
The number of stack frames to skip
Increase this value if you wrap the Logger in custom helper functions to ensure the reported caller reflects the actual log origin.
Example
logger.SetCallerOffset(2)
Resource management
Close
Stops the background worker and flushes all remaining log entries.
You must call Close before your application exits to ensure no asynchronous logs are lost. It safely decrements the worker reference count and stops the worker when the count reaches zero. Calling Close on a synchronous Logger has no effect.
Example
Sync
Flushes any buffered log entries to the underlying writer.
func (l *Logger) Sync() error
Delegates to the worker’s sync method for asynchronous loggers, or calls Sync on the underlying io.Writer if it implements the interface. Use this to ensure critical logs are written immediately.
Example
logger.Error("critical error")
if err := logger.Sync(); err != nil {
fmt.Fprintf(os.Stderr, "failed to sync logger: %v\n", err)
}