journal
journal
¶
Dependency-free writer for the systemd journal's native datagram protocol.
Every terok- package that wants its logs to reach journald routes through
JournalWriter. The wire format is
implemented directly against /run/systemd/journal/socket — no*
systemd-python / libsystemd binding — because the fleet must run
unchanged on non-systemd inits (OpenRC and friends), where
journald_available simply reports
False and callers fall back to a file.
The socket's presence is the systemd-is-here probe: it is precise where a "which init am I under" guess is not — a container on a systemd host often has no journal socket, and that case must degrade to a file too.
Should a hard systemd-python dependency ever become acceptable on a
subset of hosts, a binding-backed writer can be slotted in behind this same
class surface without touching a single caller — the point of keeping the
protocol here, behind one seam.
JOURNALD_SOCKET = Path('/run/systemd/journal/socket')
module-attribute
¶
Local journald datagram socket; its presence is the systemd-is-here probe.
PRIORITY_INFO = 6
module-attribute
¶
syslog info priority — the default for a plain entry.
PRIORITY_WARNING = 4
module-attribute
¶
syslog warning priority.
PRIORITY_ERR = 3
module-attribute
¶
syslog err priority.
__all__ = ['JOURNALD_SOCKET', 'PRIORITY_ERR', 'PRIORITY_INFO', 'PRIORITY_WARNING', 'JournalWriter', 'encode_field', 'encode_fields', 'journald_available']
module-attribute
¶
JournalWriter(identifier, *, static_fields=None)
¶
Send structured entries to journald over the native datagram socket.
The identifier (SYSLOG_IDENTIFIER) and any static_fields are
encoded once at construction and prefixed onto every entry; per-entry
MESSAGE / PRIORITY / extra fields are appended on
send. Every send is
best-effort: a full datagram buffer or a vanished socket is swallowed so
logging never propagates a failure into the caller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identifier
|
str
|
|
required |
static_fields
|
dict[str, str] | None
|
Extra fields repeated on every entry (e.g.
|
None
|
Connect the datagram socket and precompute the static field block.
Source code in src/terok_util/journal.py
send(message, *, priority=PRIORITY_INFO, **fields)
¶
Emit one journal entry (best-effort; never raises).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The |
required |
priority
|
int
|
syslog priority (0-7); defaults to |
PRIORITY_INFO
|
**fields
|
str
|
Extra journal fields for this entry (journald upper-cases
field names by convention, e.g. |
{}
|
Source code in src/terok_util/journal.py
journald_available()
¶
Return True when a local journald datagram socket is accepting.
A plain is_socket probe: on non-systemd hosts (or containers with no
forwarded journal) the path is absent and callers route to a file
instead. Never raises — an unreadable path is reported as unavailable.
Source code in src/terok_util/journal.py
encode_field(name, value)
¶
Encode one journal field in the native export format.
Newline-free values take the compact NAME=value\n form; a value
containing a newline switches to the NAME\n<64-bit LE length><value>\n
binary form journald mandates for multi-line data.