How to Configure Logging with Zap in Gorig's utils/logger Package

Gorig's utils/logger package provides a centralized Zap-based logging system that supports development and production modes, configurable via the utils/cofigure package and injectable through HTTP middleware.

Gorig is an open-source Go framework that leverages Uber's Zap library for high-performance structured logging. The utils/logger package serves as the central logging facility, offering configurable encoders, dynamic log levels, and seamless integration with the framework's configuration and middleware systems.

Understanding Gorig's Logger Architecture

Core Components in utils/logger/logger.go

The heart of the logging system resides in utils/logger/logger.go. This file defines the New function that constructs a Zap Logger instance from a configuration struct. The initialization routine supports toggling between development encoders (human-readable, colorized console output) and production encoders (structured JSON), setting log levels, and enabling caller information or stack traces.

Configuration Integration with utils/cofigure

Logger settings are loaded through Gorig's configuration system in utils/cofigure/cfg.go. The package reads environment variables or configuration files and maps them to the logger's initialization parameters. This separation of concerns allows you to change logging behavior without modifying application code.

How to Initialize and Configure the Zap Logger

Creating a Logger Instance

To create a configured logger, invoke the New function with a configuration map or struct. The function returns a *zap.Logger that you can assign to the package's global Default variable.

package main

import (
    "github.com/jom-io/gorig/utils/logger"
    "github.com/spf13/viper"
    "go.uber.org/zap"
)

func main() {
    // Load configuration using Viper or Gorig's configure package
    viper.SetDefault("log.level", "debug")
    viper.SetDefault("log.format", "json")
    viper.SetDefault("log.development", false)

    // Initialize the logger
    zapLogger, err := logger.New(viper.AllSettings())
    if err != nil {
        panic(err)
    }

    // Set as the global default
    logger.Default = zapLogger

    // Log application startup
    logger.Default.Info("application started",
        zap.String("mode", "production"),
    )
}

Configuration Options and Environment Variables

The logger recognizes several configuration keys, typically prefixed with log.:

  • log.level – Sets the minimum log level (debug, info, warn, error).
  • log.format – Chooses the output format (json for production, console for development).
  • log.development – Boolean flag that enables development mode with human-readable output and stack traces.
  • log.outputPaths – Array of output destinations (e.g., ["stdout"] or file paths).

These values are typically defined in utils/cofigure/cfg.go and passed to the logger during initialization.

Using the Logger in Your Application

Global Logger Access

Once initialized, the logger.Default variable provides package-level access to the configured Zap instance. Import github.com/jom-io/gorig/utils/logger and call methods like logger.Info(), logger.Error(), or logger.Debug() directly.

import "github.com/jom-io/gorig/utils/logger"

func ProcessData() {
    logger.Info("starting data processing")
    
    if err := validate(); err != nil {
        logger.Error("validation failed", zap.Error(err))
        return
    }
    
    logger.Info("processing completed successfully")
}

Request-Scoped Logging with HTTP Middleware

For web applications, Gorig's HTTP middleware in httpx/mid.logger.go injects the logger into request contexts. This enables request-scoped logging without manual parameter passing.

import (
    "github.com/gin-gonic/gin"
    "github.com/jom-io/gorig/utils/logger"
    "go.uber.org/zap"
)

func MyHandler(c *gin.Context) {
    // Retrieve logger from request context
    log := logger.FromContext(c.Request.Context())
    
    log.Debug("handling request", zap.String("path", c.Request.URL.Path))
    
    // Business logic
    if err := doWork(); err != nil {
        log.Error("work failed", zap.Error(err))
        c.JSON(500, gin.H{"error": "internal server error"})
        return
    }
    
    log.Info("request completed successfully")
    c.JSON(200, gin.H{"status": "ok"})
}

Testing Logger Output

When writing unit tests, you can capture log output using a custom zapcore.Core that writes to a buffer. The test suite in test/logger_test.go demonstrates this pattern.

import (
    "bytes"
    "strings"
    "testing"
    
    "github.com/jom-io/gorig/utils/logger"
    "go.uber.org/zap"
    "go.uber.org/zapcore"
)

func TestLoggerOutput(t *testing.T) {
    var buf bytes.Buffer
    
    // Create a custom core that writes to our buffer
    cfg := logger.Config{
        Level:  "debug",
        Format: "console",
        Output: []string{"stderr"},
        Writer: &buf, // Direct output to buffer for inspection
    }
    
    l, err := logger.New(cfg)
    if err != nil {
        t.Fatalf("failed to create logger: %v", err)
    }
    
    l.Info("test message", zap.String("key", "value"))
    
    output := buf.String()
    if !strings.Contains(output, "test message") {
        t.Fatalf("unexpected log output: %s", output)
    }
}

Summary

  • Gorig's utils/logger package wraps Uber's Zap library to provide structured, high-performance logging.
  • Initialize the logger using logger.New() with configuration from utils/cofigure, supporting JSON and console formats.
  • Store the instance in logger.Default for global access across your application.
  • Use httpx/mid.logger.go middleware to inject loggers into HTTP request contexts for request-scoped logging.
  • Test logging behavior by directing output to a buffer using a custom zapcore.Core as shown in test/logger_test.go.

Frequently Asked Questions

What is the default log format in Gorig?

By default, Gorig uses JSON encoding for production environments to facilitate log aggregation and parsing. When log.development is set to true in the configuration, the logger switches to a console encoder that outputs human-readable, colorized text suitable for local development.

How do I change the log level at runtime?

The log level is set during initialization via the log.level configuration key (accepted values: debug, info, warn, error). To change levels at runtime, you must reinitialize the logger with logger.New() and update the logger.Default reference. Gorig does not currently support dynamic level changes without reinitialization.

Can I write logs to a file instead of stdout?

Yes. Configure the log.outputPaths array in your configuration to include file paths instead of or in addition to stdout. For example, setting log.outputPaths to ["/var/log/app.log", "stdout"] directs logs to both a file and standard output simultaneously.

How does the logger handle panic recovery?

While the utils/logger package provides the logging facility itself, panic recovery is typically handled by the HTTP middleware in httpx/mid.logger.go. This middleware catches panics during request handling, logs the error with stack traces using the configured Zap logger, and returns an appropriate HTTP error response to the client.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →