Skip to main content

Log system

Goffee's log system is based on the standard log package. It provides a simple interface for logging messages at different severity levels, with support for file output, optional terminal output with ANSI color codes, configurable minimum log levels, and automatic log rotation backed by lumberjack.

Configuration​

The log system is configured using environment variables in your .env or .env-dev file:

#file: .env-dev
LOG_STDOUT_ENABLE=true   # Set to true to also print logs to the terminal
LOG_LEVEL=debug # Minimum log level: debug, info, warning, error

Log levels​

The available log levels are:

  • debug - Detailed debug information (cyan colored in terminal)
  • info - General informational messages (blue colored in terminal)
  • warning - Warning messages (yellow colored in terminal)
  • error - Error messages (red colored in terminal)

When a minimum level is set, messages below that level are silently discarded. For example, if LOG_LEVEL=warning, both debug and info messages will not be written.

Using the logger​

To use the logger in your application, access it via the context in your controllers:

#file: controllers/sample.go
package controllers

import (
"git.smarteching.com/goffee/core/v2"
)

func SampleController(c *core.Context) *core.Response {
loggr := c.GetLogger()

loggr.Debug("This is a debug message")
loggr.Info("This is an info message")
loggr.Warning("This is a warning message")
loggr.Error("This is an error message")

return c.Response.Json(`{"message": "check the logs"}`)
}

Terminal output with colors​

When LOG_STDOUT_ENABLE=true is set, log messages are printed to the terminal in addition to the log file. Each severity level is color-coded for easy visual scanning:

  • DEBUG messages appear with a cyan prefix
  • INFO messages appear with a blue prefix
  • WARNING messages appear with a yellow prefix
  • ERROR messages appear with a red prefix

The log file always contains plain text without ANSI color codes, making it safe to use with log processing tools.

Log file location and rotation​

The log destination (the file path) and the log rotation behaviour are not configured in main.go. Instead they live in your app's config/ package, alongside the other feature toggles (config/queue.go, config/gorm.go, ...), in a dedicated config/log.go file. main.go only wires that config in with a single call.

Goffee ships a rotating file driver, logger.LogRotatingFileDriver, built on top of lumberjack. It bounds the log file by rotating it once it reaches a maximum size, keeping a limited number of backups, deleting backups older than a set number of days, and optionally gzip-compressing the rotated files.

Configure it in config/log.go​

Create a config/log.go that returns a core.LogConfig. This is the single source of truth for where logs are written and how they rotate:

#file: config/log.go
package config

import "git.smarteching.com/goffee/core/v2"

// Retrieve the main config for the logs
func GetLogConfig() core.LogConfig {
return core.LogConfig{
Filename: "logs/app.log", // Path of the log file (relative to the app root)
MaxSize: 10, // Megabytes before rotating
MaxBackups: 3, // Maximum number of backup files to keep
MaxAge: 28, // Days to retain old backups
Compress: true, // Compress backups with gzip (.gz)
LocalTime: false, // Use local time for rotation timestamps
}
}

Filename is resolved relative to the application root (base path) unless it is already an absolute path.

Wire it in main.go​

main.go contains nothing about file paths or rotation — just this single call, which installs a LogRotatingFileDriver using the values from config/log.go:

#file: main.go
// Handle the logs (rotation is configured in config/log.go)
app.SetLogConfig(config.GetLogConfig())

App.SetLogConfig is a convenience shortcut over the lower-level App.SetLogsDriver. If you prefer to build the driver by hand, the equivalent is:

#file: main.go
app.SetLogsDriver(&logger.LogRotatingFileDriver{
Config: logger.LogRotationConfig{
Filename: path.Join(basePath, "logs/app.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 28,
Compress: true,
},
})

Rotation parameters​

ParameterMeaningNotes
FilenamePath of the active log file.Backups are written next to it, e.g. app-2026-01-02T15-04-05.000.log.
MaxSizeMaximum size in megabytes before the file is rotated.0 uses lumberjack's default of 100.
MaxBackupsMaximum number of old log files to retain.0 keeps all backups.
MaxAgeMaximum number of days to retain old log files.0 keeps them forever.
CompressGzip rotated files (.gz) when true.Saves disk space at a small CPU cost.
LocalTimeUse local time for the rotation timestamps.When false (default), UTC is used.
note

Rotation is performed lazily: lumberjack rotates on the next write once the active file exceeds MaxSize. A freshly created file is not rotated until the threshold is crossed by an actual write, so a single huge burst can briefly exceed the limit.

Legacy file driver​

If you need a plain file with no rotation — for a quick prototype, or when an external log processor handles rotation for you — the legacy logger.LogFileDriver still exists. You would pass the file path directly, bypassing config/log.go:

#file: main.go
app.SetLogsDriver(&logger.LogFileDriver{
FilePath: path.Join(basePath, "logs/app.log"),
})

This driver does not honour the rotation settings in config/log.go. New apps should prefer LogRotatingFileDriver via app.SetLogConfig(config.GetLogConfig()).