Formatter types
TheFormatter type (options.go:32-39) defines how log entries are serialized:
TextFormatter (default)
TextFormatter (options.go:35-36) produces colorized, key-value formatted output optimized for human readability:- Colorized output using ANSI escape codes
- Automatic timestamp formatting with configurable layout
- Key-value pairs with smart quoting (values with spaces are quoted)
- Optimized for terminal viewing and local development
formatLogText() function (formatter.go:40-237) writes directly to a pooled buffer without allocations for common types.
JSONFormatter
JSONFormatter (options.go:38) produces structured JSON with one log entry per line:- One JSON object per line (newline-delimited JSON)
- Zero-allocation encoding for common types
- Compatible with log aggregation systems (Elasticsearch, CloudWatch, Datadog)
- Machine-readable and easy to parse
formatLogJSON() function (formatter.go:243-336) uses a custom zero-allocation JSON encoder (formatter.go:553-556) that bypasses Go’s standard json.Marshal.
Configuring formatters
Set the formatter viaOptions.Formatter (options.go:128-129):
If you don’t specify a formatter, Velo defaults to TextFormatter (options.go:128).
Text formatting details
Field rendering
The text formatter processes fields in this order (formatter.go:111-234):- Logger-attached fields (set via
With()) - Call-site loosely typed fields
- Logger-attached typed fields
- Context-extracted fields
- Call-site typed fields
Colorization
Velo uses thelipgloss library for terminal styling. The DefaultStyles() function defines colors for:
- Timestamps (formatter.go:47)
- Log levels (different colors per level)
- Keys and values
- Separators (
=) - Caller information
_defaultStyles (formatter.go:34) to avoid repeated allocations.
Value quoting
The text formatter (formatter.go:103-107, 224-228) automatically quotes values containing spaces or equals signs:JSON formatting details
Time encoding
JSON timestamps support three formats viaOptions.TimeFormat (options.go:99):
Zero-allocation encoding
The JSON formatter implements custom encoding for common types to eliminate allocations:appendJSONString() function (formatter.go:772-784) uses a fast path that only escapes when necessary.
Field types
The JSON encoder (formatter.go:658-736) handles strongly typed fields efficiently:- Primitives: Strings, ints, bools serialize directly
- Time: Encoded according to
TimeFormat - Duration: Serialized as nanoseconds (int64)
- Objects: Implement
ObjectMarshalerinterface - Arrays: Implement
ArrayMarshalerinterface - Slices: Special handling for
[]int,[]string,[]time.Time
Escape handling
The JSON encoder maintains a_noEscape lookup table (formatter.go:738-746) for fast character validation:
appendJSONStringEscape() function (formatter.go:786-818) uses chunked memory copies for maximum performance.
Performance characteristics
Text formatter
- Allocation: Typically 1 allocation for loosely typed fields, 0 for strongly typed
- Speed: ~48 ns/op for simple messages (README.md:98)
- Throughput: Optimized for terminal output with color rendering
JSON formatter
- Allocation: 0 allocations for strongly typed fields with pre-encoded context
- Speed: Comparable to text formatter for most workloads
- Throughput: Bypasses reflection and
json.Marshaloverhead
The JSON formatter’s custom encoder (formatter.go:553-949) eliminates map allocations and reflection that Go’s standard library requires. This is a key performance optimization.
Entry vs. direct formatting
Velo uses two formatting paths:Direct formatting (fast path)
TheformatLogText() and formatLogJSON() functions (formatter.go:40, 243) bypass the Entry struct allocation:
Entry formatting (compatibility)
TheformatEntry() function (formatter.go:339-348) accepts an Entry struct for compatibility with interfaces that require materialized log entries:
Custom formatters
Velo does not currently support custom formatters. TheFormatter type is a simple enum with two values. To implement custom formatting:
- Use
TextFormatterand post-process the output - Wrap the logger’s output writer with your own
io.Writerthat transforms the output - Contribute a PR to add a custom formatter interface