Velo provides a clean, developer-friendly API for structured logging. This guide covers the essential logging methods and how to use them effectively.
Creating a logger
The simplest way to get started is with the New function, which creates a logger writing to the provided io.Writer:
logger := velo . New ( os . Stderr )
defer logger . Close () // Always flush the buffer before exit
For quick debugging or simple applications, you can use the global default logger:
velo . Info ( "application started" )
velo . Debug ( "debug information" , "version" , "1.0.0" )
Always call Close() on your logger before your application exits to ensure all buffered logs are written. Failing to close the logger may result in lost log entries.
Log levels
Velo supports standard log levels from most to least verbose:
Debug
Use for detailed diagnostic information during development: logger . Debug ( "processing request" , "endpoint" , "/api/users" )
Info
Use for general informational messages: logger . Info ( "server started" , "port" , 8080 )
Warn
Use for potentially harmful situations: logger . Warn ( "high memory usage" , "usage" , "85%" )
Error
Use for error events that might still allow the application to continue: logger . Error ( "failed to connect to database" , "error" , err )
Panic
Logs a message then calls panic(): logger . Panic ( "critical failure" , "component" , "auth" )
Fatal
Logs a message then calls os.Exit(1): logger . Fatal ( "cannot recover" , "reason" , "config missing" )
Logging with fields
Velo accepts loosely-typed key-value pairs for structured logging:
logger . Info ( "failed to fetch URL" ,
"url" , url ,
"attempt" , 3 ,
"backoff" , time . Second ,
)
Fields are always provided as alternating key-value pairs. The keys should be strings, and values can be any type.
For maximum performance and zero allocations, use the strongly-typed fields API covered in the typed fields guide .
For situations where you need string formatting, use the *f methods:
logger . Infof ( "processing %d items from %s " , count , source )
logger . Errorf ( "connection failed after %d attempts" , retries )
Formatted logging methods use fmt.Sprintf internally, which incurs allocation overhead. Avoid using these in performance-critical paths.
Dynamic log levels
You can change the minimum log level at runtime:
logger . SetLevel ( velo . DebugLevel ) // Show all debug logs
logger . SetLevel ( velo . WarnLevel ) // Only show warnings and above
The logger discards any messages below the configured level, which helps reduce overhead in production.
Default logger operations
Velo provides package-level functions that operate on the global default logger:
velo . Info ( "using default logger" )
velo . SetLevel ( velo . ErrorLevel )
velo . Debug ( "this won't appear" ) // Below ErrorLevel
You can replace the default logger:
customLogger := velo . NewWithOptions ( os . Stdout , velo . Options {
ReportTimestamp : true ,
Formatter : velo . JSONFormatter ,
})
velo . SetDefault ( customLogger )
Flushing logs
For asynchronous loggers, use Sync() to flush buffered entries immediately:
logger . Error ( "critical error occurred" , "error" , err )
logger . Sync () // Ensure the error is written immediately
This is particularly useful before application shutdown or after logging critical errors.
Next steps
Typed fields Use strongly-typed fields for zero-allocation logging
Configuration Configure formatters, timestamps, and advanced options