exlab_wizard.logging.format#

Structured log formatter and secret-redaction helpers. Backend Spec §16.4, §16.10.

This module owns the canonical wizard.<hostname>.log line shape:

<UTC ISO 8601 timestamp> [<LEVEL:5>] [host:..] [equip:..] [proj:..] [kind:..] [run:..] <message>

The format string is fixed – downstream tooling (log aggregation scripts, the Detail-pane log viewer, the Frontend-spec recovery flows) parses this shape. Adding a new structured tag is a deliberate spec change to §16.4 and this module.

Two public surfaces:

  • StructuredTagFormatter – a logging.Formatter subclass that consults the per-task contextvars from logging/context.py at emit time and renders only the tags whose values are set.

  • redact_secret() – masks credential-bearing substrings (URL user:password segments, Bearer ... tokens, Authorization: ... headers) before they reach a log line. Component authors are required by §16.10 to wrap any URL or auth-bearing string they log through this helper.

Functions

redact_secret(value)

Mask credential-bearing substrings inside value.

Classes

StructuredTagFormatter([fmt, datefmt, ...])

Formatter that renders the §16.4 structured-tag log line.

class exlab_wizard.logging.format.StructuredTagFormatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)[source]#

Bases: Formatter

Formatter that renders the §16.4 structured-tag log line.

Reads the active per-task context vars at format time so a logger instance created at module import (with no run context) still emits correctly tagged lines once a set_run_context block wraps the actual log call.

Output shape:

2026-04-17T14:31:55Z [INFO ] [host:labpc-04] [equip:CONFOCAL_01] ...

Tags are omitted entirely (no empty placeholder) when their context var is unset. The level field is left-padded to 5 characters so columns line up across INFO / WARN / DEBUG / ERROR lines.

format(record)[source]#

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

Parameters:

record (LogRecord)

Return type:

str

exlab_wizard.logging.format.redact_secret(value)[source]#

Mask credential-bearing substrings inside value.

Replaces three classes of secret with literal ***:

  1. URL user-info password: https://user:pw@host -> https://user:***@host.

  2. Bearer <token> tokens -> Bearer ***.

  3. Authorization: <value> headers -> Authorization: ***.

The function is intentionally idempotent and safe to call on strings that contain no secrets – it returns those unchanged. Component authors are required by §16.10 to wrap any URL or auth-bearing string in this helper before logging.

The returned string preserves the rest of the input verbatim so log lines remain readable around the redacted segment.

Parameters:

value (str)

Return type:

str