Systemd Journal Integration¶
stogger sends structured log events to the systemd journal when running under systemd. This avoids duplicate timestamps and level indicators that appear when console output is captured by the journal.
When You Need This¶
Any Python service that runs as a systemd unit benefits from journal integration:
Console output in systemd gets prefixed with journal metadata (timestamp, unit name) — stogger’s own formatting adds a second set, producing redundant headers in
journalctl.The journal renderer writes native journal fields (
PRIORITY,SYSLOG_IDENTIFIER,CODE_LINE) instead of formatted text lines.Console logging is automatically suppressed when
JOURNAL_STREAMis detected.
Installation¶
uv add stogger-systemd
stogger-systemd pulls in systemd-python (Linux-only) and declares stogger as a dependency. No code changes required — init_logging() discovers the package at runtime.
Configuration¶
Settings live in [tool.stogger] in pyproject.toml:
[tool.stogger]
enable_systemd = true
systemd_facility = 128 # optional: syslog facility code (default: LOG_LOCAL0 = 128)
enable_systemd¶
Controls whether init_logging() attempts to register the journal target.
true(default) — importstogger-systemdand register the journal logger.false— skip journal registration entirely. No import attempt.
systemd_facility¶
Syslog facility code passed to SystemdJournalRenderer. Maps to syslog.LOG_LOCALn constants.
null/ unset (default) — usesLOG_LOCAL0(128).Integer value — passed through to the renderer unchanged.
Most services never need to change this. It matters only when filtering journal output by facility.
How It Works¶
init_logging() follows this sequence:
Build the loggers dict (file, console).
Suppress console output when
JOURNAL_STREAMenv var is set (systemd sets this for every service).If
enable_systemdistrue, attemptfrom stogger_systemd import get_journal_logger_factory.On
ImportError(package not installed), log a one-time info message and continue without journal.Configure structlog with all available targets.
Fallback Behavior¶
Condition |
Behavior |
|---|---|
|
Journal + file. Console suppressed. |
|
Journal target registers but writes nothing. Console + file active. |
|
Info message logged. Console + file active. |
|
Silent skip. Console + file active. |
No configuration produces errors or warnings in non-systemd environments.
Journal Fields¶
SystemdJournalRenderer transforms each event into journal-native fields:
Field |
Source |
|---|---|
|
Mapped from log level ( |
|
|
|
|
|
Source file and line number |
|
Event ID + formatted |
All event keys |
Uppercased (e.g. |
Querying with journalctl¶
# All logs from your service
journalctl -u myapp.service
# Filter by syslog identifier
journalctl -t myapp
# Errors only
journalctl -t myapp -p err
# Specific event by ID
journalctl -t myapp MESSAGE="user-login*"
# Structured field query
journalctl -t myapp USER_ID=123
# Follow live output
journalctl -u myapp.service -f
# Since a specific time
journalctl -u myapp.service --since "1 hour ago"
systemd Unit Example¶
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/myapp
SyslogIdentifier=myapp
StandardOutput=journal
StandardError=journal
# Let stogger detect journal via JOURNAL_STREAM
# No special configuration needed
[Install]
WantedBy=multi-user.target
The SyslogIdentifier in the unit file and syslog_identifier in [tool.stogger] should match. This ensures consistent filtering with journalctl -t.
NixOS Example¶
For NixOS deployments, the service definition fits into the system configuration:
systemd.services.myapp = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = "${pkgs.myapp}/bin/myapp";
SyslogIdentifier = "myapp";
StandardOutput = "journal";
StandardError = "journal";
};
};
Troubleshooting¶
Duplicate entries in journalctl¶
Console logging is not suppressed. This happens when JOURNAL_STREAM is not set in the service environment. Verify with:
systemctl show myapp.service -p Environment
Under normal systemd operation, JOURNAL_STREAM is always present.
“stogger-systemd not available” message¶
The package is not installed. Add it to your dependencies:
uv add stogger-systemd
Journal fields are empty or missing¶
Check that enable_systemd is not set to false in [tool.stogger]. The default is true, so this only applies if explicitly disabled.
systemd-python fails to install¶
systemd-python requires libsystemd headers. On NixOS this is handled automatically. On other distributions:
# Debian/Ubuntu
apt install libsystemd-dev
# Fedora
dnf install systemd-devel