go-log4g
September 1, 2026 · View on GitHub
Log4g provides Log4j-style configuration and pattern layouts for
Go's standard log/slog logging facade. Applications can use
standard slog directly or the optional log4g facade for {}
parameterized messages.
Initialization
go-log4g configures the standard log/slog logger automatically when
the core package is initialized.
Import core as a blank import in the application bootstrap:
import _ "github.com/go-log4g/core"
During initialization, Log4g searches for a configuration file in this order:
- The file specified by the
--log4g.configurationFilecommand-line property - The file specified by the
LOG4G_CONFIGURATION_FILEenvironment variable - config/log4g.yaml
- log4g.yaml
The first existing configuration file is loaded.
If no configuration file is found, Log4g installs its default
configuration and logs ERROR and higher events to the console.
If a configuration file is found but cannot be read, parsed, or
processed, Log4g reports the error to stderr and falls back to the
default configuration.
Once initialized, use standard slog normally:
slog.Info("Application started")
slog.Debug("Loading user", "userId", 123)
Or use the optional log4g facade for {} parameterized messages:
import "github.com/go-log4g/core/log4g"
log4g.Info("User {} authenticated", 123)
log4g.Debug("Loaded {} records in {}", count, elapsed)
Testing
Go runs tests with the package directory as the working directory rather
than the module root. Log4g automatically detects the Go test runner and
locates the module root by searching parent directories for go.mod.
When running tests, configuration is resolved in the following order:
- The file specified by the
--log4g.configurationFilecommand-line property - The file specified by the
LOG4G_CONFIGURATION_FILEenvironment variable module/config/log4g-test.yamlmodule/log4g-test.yamlmodule/config/log4g.yamlmodule/log4g.yaml
The first existing configuration file is loaded.
This allows a project to keep a dedicated test configuration without any additional test setup:
config/
log4g.yaml
log4g-test.yaml
log4g-test.yaml is used automatically when running tests, while
log4g.yaml remains the fallback when no test-specific configuration is
provided.
Configuration
Create config/log4g.yaml:
properties:
pattern: "%d{yyyy-MM-dd HH:mm:ss.SSS}{UTC} %-5p %c:%L - %m%n"
appenders:
stdout:
type: console
target: stdout
filter:
type: levelRange
minLevel: debug
maxLevel: warn
layout:
type: pattern
pattern: "${pattern}"
stderr:
type: console
target: stderr
filter:
type: threshold
level: error
layout:
type: pattern
pattern: "${pattern}"
file:
type: file
file: logs/file.log
# append: true
# immediateFlush: true
# bufferSize: 8192
layout:
type: pattern
pattern: "${pattern}"
rollingFile:
type: rollingFile
file: logs/rollingFile.log
filePattern: logs/arch/rollingFile-%d{yyyyMMdd}-%i.log.zip
# append: true
# immediateFlush: true
# bufferSize: 8192
policies:
onStartupTriggeringPolicy:
minSize: 1B
timeBasedTriggeringPolicy:
interval: 1
# modulate: false
sizeBasedTriggeringPolicy:
size: 300MB
defaultRolloverStrategy:
# max: 7
delete:
maxAge: 30d
# maxFiles: 100
# maxTotalSize: 5GB
layout:
type: pattern
pattern: "${pattern}"
root:
level: error
appenderRefs:
- ref: stdout
- ref: stderr
- ref: file
level: warn
- ref: rollingFile
filter:
type: threshold
level: error
loggers:
playground/internal:
level: debug
playground/internal/network:
level: warn
github.com/go-beans:
level: info
github.com/go-external-config:
level: info
This configuration writes DEBUG through WARN events to stdout and
ERROR events to stderr. The root level is ERROR, while configured
logger hierarchies can override or inherit their effective level.
Logger levels
Logger levels are inherited hierarchically. A logger without an explicit level inherits the level of its nearest configured parent, falling back to the root logger.
If the root logger has no explicit level, --log4g.level is used when
provided, followed by the LOG4G_LEVEL environment variable. If none is
configured, the root level defaults to ERROR.
Properties
Configuration properties can be defined once and reused:
properties:
pattern: "%d{yyyy-MM-dd HH:mm:ss.SSS}{UTC} %-5p %c:%L - %m%n"
Properties, environment variables, and application parameters use separate namespaces:
${pattern} Configuration property
${env:LOG_PATTERN} Environment variable
${arg:log.pattern} Application parameter
Application parameters use the following form:
--log.pattern=value
Substitution is recursive, so a configuration property may itself reference another property, environment variable, or application parameter.
File appenders
file writes log events to a file:
file:
type: file
file: logs/application.log
# append: true
# immediateFlush: true
# bufferSize: 8192
layout:
type: pattern
pattern: "${pattern}"
append controls whether an existing file is appended to or truncated
when the appender is created. The default is true.
immediateFlush controls whether each log event is written immediately.
The default is true. When disabled, Log4g uses buffered asynchronous
file writes.
bufferSize specifies the size of each write buffer in bytes. The
default is 8192. Buffered file appenders use two fixed-size buffers so
logging remains memory-bounded. If file output cannot keep up with log
production, writers are blocked rather than allocating an unbounded
queue or dropping log events.
File writes are synchronized fairly, preserving the order in which concurrent log operations acquire the appender for writing.
Rolling file appenders
rollingFile extends file output with size- and time-based rollover:
rollingFile:
type: rollingFile
file: logs/application.log
filePattern: logs/arch/application-%d{yyyyMMdd}-%i.log.zip
# append: true
# immediateFlush: true
# bufferSize: 8192
policies:
onStartupTriggeringPolicy:
minSize: 1B
timeBasedTriggeringPolicy:
interval: 1
# modulate: false
sizeBasedTriggeringPolicy:
size: 300MB
defaultRolloverStrategy:
# max: 7
delete:
maxAge: 30d
# maxFiles: 100
# maxTotalSize: 5GB
layout:
type: pattern
pattern: "${pattern}"
file is the active log file. filePattern specifies the names of
rolled files. %d{...} inserts the rollover period and %i inserts the
rollover index.
Rolled files can optionally be compressed by adding a supported
compression extension to filePattern:
filePattern: logs/arch/application-%d{yyyyMMdd}-%i.log.zip
Supported rollover formats are:
.log Uncompressed
.log.gz GZIP compressed
.log.zip ZIP compressed
onStartupTriggeringPolicy rolls an existing active log file when the
appender is initialized and the file size is at least minSize. The
default minSize is 1B.
The startup rollover happens immediately during appender initialization,
before the active log file is opened. It does not wait for the first log
event.
File sizes can be specified in bytes or using B, K, KB, M, MB,
G, GB, T, and TB suffixes.
timeBasedTriggeringPolicy rolls the active file according to the
smallest time unit present in filePattern.
interval defaults to 1. An interval of 5 with a minute-based file
pattern rolls every five minutes.
modulate defaults to false. When enabled, rollover intervals are
aligned to natural time boundaries. For example, a five-minute policy
started at 10:07 rolls at 10:10, 10:15, 10:20, and so on.
sizeBasedTriggeringPolicy rolls the active file when it reaches the
configured size. The default size is 10MB.
When multiple triggering policies are configured, rollover occurs when any policy triggers.
defaultRolloverStrategy.max defaults to 7. Index 1 is the oldest
retained rolled file and the maximum index is the newest. Once the
maximum number of files for a rollover period is reached, the oldest
file is removed and the remaining indexes are shifted down.
For example:
application.log active
application-20260817-1.log oldest
application-20260817-2.log
...
application-20260817-7.log newest
defaultRolloverStrategy.delete can remove expired rolled files after a
successful rollover. Only files matching this appender's filePattern are considered for
deletion. Other files in the same directory are not affected.
All retention limits are optional:
maxAge removes files older than the configured duration. Go duration
syntax such as 12h and 24h is supported, with d also supported
for days, for example 7d or 30d.
maxFiles limits the total number of retained rolled files.
maxTotalSize limits their combined size and accepts the same file
size syntax as triggering policies, for example 500MB or 5GB.
When multiple limits are configured, age retention is applied first,
followed by file count and total size. When a count or size limit is
exceeded, the oldest files are removed first.
Retention is evaluated after each successful rollover; it does not run
as a background cleanup task.
Loggers
Loggers configuration is hierarchical. For example:
playground/internal/app
also matches:
playground/internal/app/Service1
playground/internal/app/service/UserService
Pattern layout
The configured pattern:
%d{yyyy-MM-dd HH:mm:ss.SSS}{UTC} %-5p %c:%L - %m%n
produces output such as:
2026-08-13 12:34:56.789 INFO playground/internal/app/Service1:23 - Service initialized
Date/time formats
%d accepts either a Java-style date/time pattern or one of the
predefined formats.
Without an explicit format, DEFAULT is used:
%d
%d{DEFAULT}
→ 2026-08-17 12:34:56,789
Supported predefined formats:
DEFAULT
→ 2026-08-17 12:34:56,789
ISO8601
→ 2026-08-17T12:34:56,789
ISO8601_BASIC
→ 20260817T123456,789
ABSOLUTE
→ 12:34:56,789
DATE
→ 17 Aug 2026 12:34:56,789
COMPACT
→ 20260817123456789
Custom Java-style patterns are also supported:
%d{yyyy-MM-dd HH:mm:ss.SSS}
→ 2026-08-17 12:34:56.789
%d{yyyyMMdd-HHmmss}
→ 20260817-123456
A timezone can be supplied as the second date option:
%d{yyyy-MM-dd HH:mm:ss.SSS}{UTC}
→ 2026-08-17 12:34:56.789
Supported patterns
%d{pattern} Date/time
%d{pattern}{UTC} Date/time in UTC
%p Log level
%level Same as %p
%c Logger name
%logger Same as %c
%M Method/function name
%method Same as %M
%F Source file
%file Same as %F
%L Source line
%line Same as %L
%m Message
%msg Same as %m
%message Same as %m
%X{key} MDC value
%X All MDC values
%n Platform newline
%% Literal %
Examples:
%d{yyyy-MM-dd HH:mm:ss.SSS}{UTC}
→ 2026-08-13 12:34:56.789
%p
→ INFO
%c
→ playground/internal/app/Service1
%M
→ AfterPropertiesSet
%F:%L
→ Service1.go:23
%m
→ Service initialized
%X{requestId}
→ 8f24...
%X
→ {requestId=8f24..., userId=123}
Width and alignment
A minimum width can be specified before a converter:
%5p minimum width 5, right aligned
%-5p minimum width 5, left aligned
Example:
%-5p
produces aligned levels:
DEBUG
INFO
WARN
ERROR
Width is also useful for optional MDC values. For example, a compact request ID can use the last UUID section:
[%12X{requestId}]
With a request ID:
[446655440000]
Without a request ID:
[ ]
Logger name precision
Given:
playground/internal/app/Service1
the following patterns produce:
%c → playground/internal/app/Service1
%c{1} → Service1
%c{2} → app/Service1
%c{3} → internal/app/Service1
%c{-1} → internal/app/Service1
%c{-2} → app/Service1
Positive precision keeps rightmost components. Negative precision removes components from the left.
Logger name abbreviation
Given:
org/apache/commons/test/Foo
simple abbreviation:
%c{1.} → o/a/c/t/Foo
%c{2.} → or/ap/co/te/Foo
Explicit component rules:
%c{1.1.1.*}
→ o/a/c/test/Foo
Here the first three components are shortened to one character and *
leaves the remaining components unchanged.
Dynamic abbreviation:
%c{1.2.*}
→ o/a/c/test/Foo
Here leading components are shortened to one character while the last two components are preserved.
Another example:
%c{1.3.*}
→ o/a/commons/test/Foo
This style is useful for Go logger names because a long module prefix can be abbreviated while the local package and type remain readable.
MDC
MDC associates logging values with a context.Context.
ctx = mdc.Put(ctx, "requestId", requestId)
ctx = mdc.Put(ctx, "userId", userId)
log4g.InfoContext(ctx, "Processing request")
Use one MDC value in a pattern:
%X{requestId}
or all values:
%X
mdc.Put follows Go context semantics and returns a derived context:
ctx = mdc.Put(ctx, "requestId", requestId)
Each derived MDC context contains the complete MDC snapshot, so
subsequent Put operations retain previously added values.
Extension appenders
Additional appender types can be provided by external go-log4g modules.
For example, go-log4g-shared provides the sharedRollingFile appender for multiple processes writing to the same rolling log file.
Import the extension package to register its appender:
import _ "github.com/go-log4g/shared"
It can then be used in the standard Log4g configuration:
appenders:
shared:
type: sharedRollingFile
file: logs/shared.log
filePattern: logs/arch/shared-%d{yyyyMMddHHmm}-%i.log.zip
See the go-log4g-shared documentation for shared file locking and configuration details.