logger

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 15, 2026 License: MIT Imports: 5 Imported by: 0

README

Logger Package

Structured logging for Nivo services using zerolog.

Overview

The logger package provides a structured, performant logging solution built on zerolog. It supports context-aware logging, multiple output formats, and consistent log levels across all services.

Features

  • Zero-allocation: Based on zerolog for high performance
  • Structured logging: JSON and console output formats
  • Context-aware: Automatic request ID, user ID, correlation ID tracking
  • Multiple levels: Debug, Info, Warn, Error, Fatal
  • Flexible configuration: Per-service configuration
  • Global logger: Optional global instance for convenience

Usage

Basic Usage
package main

import (
    "github.com/1mb-dev/nivomoney/shared/logger"
)

func main() {
    // Create logger
    log := logger.NewDefault("my-service")

    // Log messages
    log.Info("service started")
    log.Debug("debug information")
    log.Warn("something might be wrong")
    log.Error("an error occurred")
}
Configuration
log := logger.New(logger.Config{
    Level:       "debug",        // debug, info, warn, error, fatal
    Format:      "json",         // json or console
    ServiceName: "identity-service",
    Output:      os.Stdout,      // optional, defaults to os.Stdout
})
Formatted Logging
log.Infof("user %s logged in", userID)
log.Debugf("processing %d transactions", count)
log.Errorf("failed to connect to %s: %v", host, err)
Structured Fields
// Add single field
log.WithField("user_id", "user-123").
    Info("user action performed")

// Add multiple fields
log.With(map[string]interface{}{
    "transaction_id": "tx-456",
    "amount":         100.50,
    "currency":       "USD",
}).Info("transaction processed")
Context-Aware Logging
ctx := context.Background()
ctx = context.WithValue(ctx, logger.RequestIDKey, "req-abc-123")
ctx = context.WithValue(ctx, logger.UserIDKey, "user-456")

// Logger will automatically include request_id and user_id
contextLog := log.WithContext(ctx)
contextLog.Info("handling request")

// Output: {"level":"info","request_id":"req-abc-123","user_id":"user-456","message":"handling request"}
Error Logging
err := doSomething()
if err != nil {
    log.WithError(err).
        Error("operation failed")
}

// Output includes error in structured format
Output Formats

Console Format (Human-readable, colored output for development):

log := logger.New(logger.Config{
    Level:       "info",
    Format:      "console",
    ServiceName: "my-service",
})

Output:

2:04PM INF service started service=my-service
2:05PM WRN high latency detected latency=250ms service=my-service
2:05PM ERR database connection failed error="connection timeout" service=my-service

JSON Format (Machine-readable, structured output for production):

log := logger.New(logger.Config{
    Level:       "info",
    Format:      "json",
    ServiceName: "my-service",
})

Output:

{"level":"info","service":"my-service","time":"2025-01-15T14:04:05Z","message":"service started"}
{"level":"warn","service":"my-service","latency":250,"time":"2025-01-15T14:05:12Z","message":"high latency detected"}
{"level":"error","service":"my-service","error":"connection timeout","time":"2025-01-15T14:05:15Z","message":"database connection failed"}
Global Logger (Optional)

For convenience, you can use a global logger instance:

// Initialize once at startup
logger.InitGlobal(logger.Config{
    Level:       "info",
    Format:      "console",
    ServiceName: "my-service",
})

// Use anywhere
logger.Info("service started")
logger.Error("something went wrong")
Integration with Services
package main

import (
    "github.com/1mb-dev/nivomoney/shared/config"
    "github.com/1mb-dev/nivomoney/shared/logger"
)

func main() {
    // Load configuration
    cfg, err := config.Load()
    if err != nil {
        panic(err)
    }

    // Initialize logger
    log := logger.New(logger.Config{
        Level:       cfg.LogLevel,
        Format:      determineFormat(cfg),
        ServiceName: cfg.ServiceName,
    })

    log.Info("service initialized")

    // Use logger throughout application
    handleRequests(log)
}

func determineFormat(cfg *config.Config) string {
    if cfg.IsDevelopment() {
        return "console"
    }
    return "json"
}
HTTP Middleware Example
func LoggingMiddleware(log *logger.Logger) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            requestID := r.Header.Get("X-Request-ID")
            if requestID == "" {
                requestID = generateRequestID()
            }

            ctx := context.WithValue(r.Context(), logger.RequestIDKey, requestID)

            reqLog := log.WithContext(ctx).WithField("method", r.Method).WithField("path", r.URL.Path)
            reqLog.Info("request received")

            next.ServeHTTP(w, r.WithContext(ctx))

            reqLog.Info("request completed")
        })
    }
}

Log Levels

  • Debug: Detailed information for diagnosing problems (not shown in production)
  • Info: General informational messages (service lifecycle, major operations)
  • Warn: Warning messages (deprecated API usage, poor performance, near errors)
  • Error: Error messages (operation failures, caught exceptions)
  • Fatal: Fatal messages that cause program termination

Context Keys

The package provides standard context keys for common fields:

  • logger.RequestIDKey - HTTP request ID
  • logger.UserIDKey - Authenticated user ID
  • logger.CorrelationIDKey - Distributed tracing correlation ID

Best Practices

  1. Use Structured Fields: Prefer structured fields over formatted strings

    // Good
    log.WithField("user_id", userID).Info("user logged in")
    
    // Less ideal
    log.Infof("user %s logged in", userID)
    
  2. Log at Appropriate Levels:

    • Debug: Development debugging only
    • Info: Important service events
    • Warn: Recoverable issues
    • Error: Operation failures
    • Fatal: Critical failures (use sparingly)
  3. Include Context: Always propagate context for request tracking

    contextLog := log.WithContext(ctx)
    
  4. Avoid Logging Secrets: Never log passwords, tokens, or sensitive data

  5. Use JSON in Production: JSON format is easier to parse and analyze

Performance

Zerolog is one of the fastest Go logging libraries:

  • Zero allocation in hot paths
  • Minimal CPU overhead
  • Efficient JSON encoding

Testing

go test ./shared/logger/...
go test -cover ./shared/logger/...

Documentation

Overview

Package logger provides structured logging for Nivo services using zerolog.

Index

Constants

View Source
const (
	// RequestIDKey is the context key for request IDs.
	RequestIDKey contextKey = "request_id"
	// UserIDKey is the context key for user IDs.
	UserIDKey contextKey = "user_id"
	// CorrelationIDKey is the context key for correlation IDs.
	CorrelationIDKey contextKey = "correlation_id"
)

Variables

This section is empty.

Functions

func Debug

func Debug(msg string)

Debug logs a debug message using the global logger.

func Error

func Error(msg string)

Error logs an error message using the global logger.

func Fatal

func Fatal(msg string)

Fatal logs a fatal message using the global logger and exits.

func Info

func Info(msg string)

Info logs an info message using the global logger.

func InitGlobal

func InitGlobal(cfg Config)

InitGlobal initializes the global logger instance.

func Warn

func Warn(msg string)

Warn logs a warning message using the global logger.

Types

type Config

type Config struct {
	Level       string // debug, info, warn, error
	Format      string // console, json
	ServiceName string
	Output      io.Writer
}

Config holds logger configuration.

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

Logger wraps zerolog.Logger with additional functionality.

func Global

func Global() *Logger

Global returns the global logger instance.

func New

func New(cfg Config) *Logger

New creates a new Logger instance with the given configuration.

func NewDefault

func NewDefault(serviceName string) *Logger

NewDefault creates a logger with default configuration.

func NewFromEnv

func NewFromEnv(serviceName string) *Logger

NewFromEnv creates a logger based on environment variables. Uses LOG_LEVEL (default: info) and LOG_FORMAT (default: json in production, console otherwise). Environment is determined by ENV or ENVIRONMENT variable.

func (*Logger) Debug

func (l *Logger) Debug(msg string)

Debug logs a debug level message.

func (*Logger) Debugf

func (l *Logger) Debugf(format string, args ...interface{})

Debugf logs a formatted debug level message.

func (*Logger) Error

func (l *Logger) Error(msg string)

Error logs an error level message.

func (*Logger) Errorf

func (l *Logger) Errorf(format string, args ...interface{})

Errorf logs a formatted error level message.

func (*Logger) Fatal

func (l *Logger) Fatal(msg string)

Fatal logs a fatal level message and exits.

func (*Logger) Fatalf

func (l *Logger) Fatalf(format string, args ...interface{})

Fatalf logs a formatted fatal level message and exits.

func (*Logger) GetZerologLogger

func (l *Logger) GetZerologLogger() zerolog.Logger

GetZerologLogger returns the underlying zerolog.Logger for advanced usage.

func (*Logger) Info

func (l *Logger) Info(msg string)

Info logs an info level message.

func (*Logger) Infof

func (l *Logger) Infof(format string, args ...interface{})

Infof logs a formatted info level message.

func (*Logger) Warn

func (l *Logger) Warn(msg string)

Warn logs a warning level message.

func (*Logger) Warnf

func (l *Logger) Warnf(format string, args ...interface{})

Warnf logs a formatted warning level message.

func (*Logger) With

func (l *Logger) With(fields map[string]interface{}) *Logger

With returns a new logger with additional fields.

func (*Logger) WithContext

func (l *Logger) WithContext(ctx context.Context) *Logger

WithContext returns a new logger with context values added.

func (*Logger) WithError

func (l *Logger) WithError(err error) *Logger

WithError returns a new logger with error field added.

func (*Logger) WithField

func (l *Logger) WithField(key string, value interface{}) *Logger

WithField returns a new logger with a single field added.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL