Documentation Index
Fetch the complete documentation index at: https://mnah05-boiler-go-21-79.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
The logger package provides structured logging using zerolog with support for multiple output destinations including stdout, file, or both. It includes request-scoped logging and context extraction utilities.
Types
OutputConfig
Defines where logs should be written.
type OutputConfig struct {
// FilePath is the path to the log file. If empty, no file logging.
FilePath string
// Stdout enables console output.
Stdout bool
// StdoutOnly disables file output and only logs to stdout.
StdoutOnly bool
}
Path to the log file. If empty, no file logging occurs
Enables console output with human-readable formatting
Disables file output and only logs to stdout
Functions
New
Creates a new logger with default configuration (stdout only).
func New() zerolog.Logger
Returns: zerolog.Logger - Logger instance configured for stdout
Configuration:
- Human-readable console output
- Timestamp:
2006-01-02 15:04:05 format
- Log level: Info
NewWithOutput
Creates a new logger with configurable output destinations.
func NewWithOutput(cfg OutputConfig) zerolog.Logger
Configuration for output destinations
Returns: zerolog.Logger - Configured logger instance
Behavior:
- Creates log directory if it doesn’t exist
- Falls back to stdout on file errors
- Supports multi-writer for both stdout and file
- Automatically adds timestamps
- Sets Info log level
Global
Returns the global fallback logger instance.
func Global() zerolog.Logger
Returns: zerolog.Logger - Global logger instance
Usage: Used when a request-scoped logger is not available. Initialized lazily on first access.
FromEchoContext
Extracts the request-scoped logger from Echo context.
func FromEchoContext(c echo.Context) zerolog.Logger
Echo request context containing the logger
Returns: zerolog.Logger - Request-scoped logger with request_id
Note: This function is typically used in handlers where the logger has been injected by the RequestLogger middleware.
Usage
Basic logging
import "boiler-go/pkg/logger"
func main() {
// Create a basic logger
log := logger.New()
// Log messages
log.Info().Msg("application started")
log.Error().Err(err).Msg("operation failed")
log.Debug().Str("user_id", id).Msg("processing request")
}
File logging
// Log to file only
log := logger.NewWithOutput(logger.OutputConfig{
FilePath: "logs/app.log",
Stdout: false,
StdoutOnly: false,
})
Dual output (stdout and file)
// Log to both stdout and file
log := logger.NewWithOutput(logger.OutputConfig{
FilePath: "logs/app.log",
Stdout: true,
StdoutOnly: false,
})
Configuration-based logging
// From cmd/api/main.go and cmd/worker/main.go
func newLogger(cfg *config.Config, defaultFile string) zerolog.Logger {
outputCfg := logger.OutputConfig{}
switch cfg.LogOutput {
case "stdout":
outputCfg.Stdout = true
outputCfg.StdoutOnly = true
case "file":
outputCfg.Stdout = false
outputCfg.StdoutOnly = false
outputCfg.FilePath = cfg.LogFile
if outputCfg.FilePath == "" {
outputCfg.FilePath = defaultFile
}
case "both":
outputCfg.Stdout = true
outputCfg.StdoutOnly = false
outputCfg.FilePath = cfg.LogFile
if outputCfg.FilePath == "" {
outputCfg.FilePath = defaultFile
}
}
return logger.NewWithOutput(outputCfg)
}
func main() {
cfg := config.Load(logger.New())
log := newLogger(cfg, "logs/api.log")
log.Info().Msg("server starting")
}
Request-scoped logging in handlers
import (
"boiler-go/pkg/logger"
"github.com/labstack/echo/v4"
)
func (h *HealthHandler) Check(c echo.Context) error {
// Get request-scoped logger with request_id
log := logger.FromEchoContext(c)
log.Info().Msg("health check started")
if err := h.db.Ping(ctx); err != nil {
log.Error().Err(err).Msg("database health check failed")
return c.JSON(500, map[string]string{"error": "database unavailable"})
}
log.Info().Msg("health check completed")
return c.JSON(200, map[string]string{"status": "ok"})
}
Structured logging
log := logger.New()
// Add contextual fields
log.Info().
Str("user_id", userID).
Str("action", "login").
Dur("duration", time.Since(start)).
Msg("user logged in")
// Log with error
log.Error().
Err(err).
Str("operation", "database_query").
Int("retry_count", retries).
Msg("operation failed after retries")
Log levels
The logger is set to Info level by default. Available levels:
log.Trace().Msg("trace message")
log.Debug().Msg("debug message")
log.Info().Msg("info message")
log.Warn().Msg("warning message")
log.Error().Msg("error message")
log.Fatal().Msg("fatal message") // exits application
Best practices
- Use request-scoped loggers in HTTP handlers via
FromEchoContext()
- Add structured fields instead of string formatting
- Use appropriate log levels (Info for operations, Error for failures)
- Include correlation IDs via request_id for distributed tracing
- Log file paths should be configurable via environment variables