Skip to main content
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
w
io.Writer
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
w
io.Writer
The writer to output logs to. If nil, defaults to standard error.
o
Options
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.
func Default() *Logger
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)
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)
level
Level
The log level
msg
string
The log message
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)
level
Level
The log level
msg
string
The log message
fields
...Field
Strongly typed fields
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)
ctx
context.Context
The context to extract fields from
level
Level
The log level
msg
string
The log message
keyvals
...any
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)
ctx
context.Context
The context to extract fields from
level
Level
The log level
msg
string
The log message
fields
...Field
Strongly typed fields
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)
level
Level
The log level
format
string
The format string
args
...any
Format arguments
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")

Formatted level methods

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
keyvals
...any
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
fields
...Field
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
prefix
string
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)
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)
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)
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)
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)
prefix
string
The new prefix
Use this to dynamically label logs from a specific component. Example
logger.SetPrefix("[API]")

SetTimeFormat

Changes the timestamp format string.
func (l *Logger) SetTimeFormat(format string)
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)
f
TimeFunction
The new time function
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()
})

SetFormatter

Changes the Formatter used to serialize log entries.
func (l *Logger) SetFormatter(f Formatter)
f
Formatter
The new formatter
You can switch between built in formatters like JSONFormatter and TextFormatter, or provide a custom implementation. Example
logger.SetFormatter(velo.JSONFormatter)

SetCallerFormatter

Changes the function used to format caller location data.
func (l *Logger) SetCallerFormatter(f CallerFormatter)
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)
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.
func (l *Logger) Close()
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
defer logger.Close()

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

Build docs developers (and LLMs) love