Logie
A flexible structured logging package built on top of zerolog with module-level log control.
Installation
go get github.com/Michi01/logie
Features
- Module-based logging with independent log levels
- Global and per-module log level control
- Structured logging with fields
- Console output formatting
- Built-in support for common fields (hostname, PID, Go version)
- Trace-level logging support
Quick Start
package main
import "github.com/Michi01/logie"
func main() {
// Get default logger with console output
logger := logie.DefaultLogger()
// Basic logging
logger.Info("Hello, World!")
// Logging with fields
logger.WithField("user", "john").Info("User logged in")
}
Creating Loggers
Default Logger
logger := logie.DefaultLogger()
The default logger includes:
- Console output with timestamps
- Hostname
- Process ID
- Go version
- Application version (if BuildVersion is set)
Custom Logger
output := zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: time.RFC3339,
}
logger := logie.New(output)
Module-Based Logging
You can create a module logger either from the package level or from an existing logger:
// Package-level creation
logger := logie.WithModule("auth")
// Or from existing logger
authLogger := existingLogger.WithModule("auth")
// Package-level creation
logger := logie.WithFormatter(myFormatter)
// Or from existing logger
formattedLogger := existingLogger.WithFormatter(myFormatter)
Log Levels
Available levels: Trace, Debug, Info, Warn, Error, Fatal, Panic
Environment Configuration
package main
import (
"os"
"strings"
"github.com/rs/zerolog"
"github.com/Michi01/logie"
)
func init() {
// Set global log level from environment
if levelStr := os.Getenv("LOG_LEVEL"); levelStr != "" {
level := parseLogLevel(levelStr, zerolog.InfoLevel)
logie.SetGlobalLevel(level)
}
// Configure module levels from environment
// Format: MODULE_LOG_LEVEL_<MODULE>=<LEVEL>
// Example: MODULE_LOG_LEVEL_AUTH=debug
for _, env := range os.Environ() {
if !strings.HasPrefix(env, "MODULE_LOG_LEVEL_") {
continue
}
parts := strings.SplitN(env, "=", 2)
if len(parts) != 2 {
continue
}
module := strings.TrimPrefix(parts[0], "MODULE_LOG_LEVEL_")
module = strings.ToLower(module)
level := parseLogLevel(parts[1], zerolog.InfoLevel)
logie.SetModuleLevel(module, level)
}
}
// parseLogLevel converts a string level to zerolog.Level with a default fallback
func parseLogLevel(level string, defaultLevel zerolog.Level) zerolog.Level {
switch strings.ToLower(level) {
case "trace":
return zerolog.TraceLevel
case "debug":
return zerolog.DebugLevel
case "info":
return zerolog.InfoLevel
case "warn":
return zerolog.WarnLevel
case "error":
return zerolog.ErrorLevel
case "fatal":
return zerolog.FatalLevel
case "panic":
return zerolog.PanicLevel
default:
return defaultLevel
}
}
Environment Variables
LOG_LEVEL: Sets the global logging level (default: "info")
MODULE_LOG_LEVEL_<MODULE>: Sets the log level for a specific module
- Example:
MODULE_LOG_LEVEL_AUTH=debug
- Example:
MODULE_LOG_LEVEL_DATABASE=error
Usage Patterns
Global Logger
package main
import "github.com/Michi01/logie"
var log *logie.Logger
func init() {
log = logie.DefaultLogger()
}
func main() {
log.Info("Application started")
}
Dependency Injection Pattern
// auth/auth.go
package auth
type Service struct {
log *logie.Logger
}
func NewService(logger *logie.Logger) *Service {
return &Service{
log: logger.WithModule("auth"),
}
}
func (s *Service) Login(username string) {
s.log.WithField("user", username).Info("Login attempt")
}
// database/db.go
package database
type Repository struct {
log *logie.Logger
}
func NewRepository(logger *logie.Logger) *Repository {
return &Repository{
log: logger.WithModule("database"),
}
}
// main.go
package main
func main() {
logger := logie.DefaultLogger()
authService := auth.NewService(logger)
dbRepo := database.NewRepository(logger)
// Both services now have their own logger instance with module context
}
Package-Level Logger
// payments/logger.go
package payments
import "github.com/Michi01/logie"
var log *logie.Logger
func init() {
log = logie.DefaultLogger().WithModule("payments")
}
// payments/service.go
package payments
func ProcessPayment(amount float64) {
log.WithField("amount", amount).Info("Processing payment")
}
Thread Safety
All operations in Logie are thread-safe and can be used concurrently.