exlab_wizard.cache.log_writer#
Append-only writer for wizard.<hostname>.log files. Backend Spec §11.5, §16.2.4.
Low-level companion to the logger handler chain in exlab_wizard/logging/.
This module owns the canonical line shape and the on-disk append semantics
so that both the high-level StructuredTagFormatter (§16.4) and any
direct callers (e.g. the equipment-scoped file handler in §16.2.4) write
identical bytes.
The line format follows §11.5 verbatim:
<UTC ISO 8601 timestamp> [<LEVEL:5>] [host:..] [equip:..] [proj:..] [kind:..] [run:..] <message>
Two public surfaces:
format_log_line()– pure function. Given a timestamp, level, message, and optional context tags, returns a single line WITHOUT a trailing newline. Truncates messages whose UTF-8 length exceedsLOG_LINE_MAX_BYTESwith a literal...[truncated]marker (Backend §4.5).append_log_line()– side-effecting. Appends a single line to awizard.<hostname>.logfile, creating the parent.exlab-wizarddirectory if missing. Atomic up toPIPE_BUFon POSIX viaO_APPEND; on Windows themode="a"open flag passesFILE_APPEND_DATAto the OS, which makes a single short append serializable against any othermode="a"writer on the same file (Backend §4.5 same-equipment concurrency rule).
The writer here is intentionally synchronous and side-effecting; the
non-blocking emit pipeline (QueueHandler + QueueListener;
§16.2.5) wraps it so the asyncio event loop is not blocked on filesystem
writes.
Functions
|
Append a single |
|
Render a structured log line per Backend Spec §11.5 / §16.4. |
- exlab_wizard.cache.log_writer.append_log_line(path, line)[source]#
Append a single
lineto awizard.<hostname>.logfile.Creates the parent
.exlab-wizarddirectory if missing (the cache directory is allowed to not yet exist on first equipment-folder initialization). The file is opened in text-append mode with line buffering so each call ends up as onewrite()syscall.Concurrency: the file is opened with
mode="a". On POSIX this maps toO_APPEND, which makes a singlewrite()of bytes ≤PIPE_BUF(4096 on Linux) atomic against concurrent appenders. Lines longer than this cap are truncated upstream byformat_log_line()toLOG_LINE_MAX_BYTES(1024) which is well underPIPE_BUF. On Windowsmode="a"opens withFILE_APPEND_DATA; the OS serializes the actual append at the syscall boundary. See Backend §4.5 same-equipment concurrency rule.The line is appended verbatim; this function adds a single trailing newline. Callers SHOULD pass a line already truncated to
LOG_LINE_MAX_BYTESviaformat_log_line().
- exlab_wizard.cache.log_writer.format_log_line(*, timestamp_utc, level, message, host=None, equipment_id=None, project_short_id=None, run_kind=None, run_id=None)[source]#
Render a structured log line per Backend Spec §11.5 / §16.4.
Tags are omitted entirely when their argument is
None. Thelevelfield is left-padded to 5 characters so columns line up acrossINFO/WARN/DEBUG/ERRORlines. The timestamp is rendered in UTC with a trailingZ(e.g.2026-04-17T14:32:00Z) matching the example shapes in §11.5.Lines whose UTF-8 length exceeds
LOG_LINE_MAX_BYTESare truncated by trimming the message tail and appending the literal...[truncated]marker. The truncation budget is computed against the full line length (timestamp + level + tags + message), so the marker is guaranteed to fit. Messages that are already short enough are returned untouched.Returns the line WITHOUT a trailing newline; the writer adds the newline at append time.