Canonical Log Lines & Structured Logging
logging_instance emits a fixed pipe-delimited human string with no JSON
option and no trace/span fields, but OTel log-trace correlation needs
trace_id / span_id on each record. This adds a Stripe-style canonical
log line (one wide field-bag emitted per run) and a JSON logging.Formatter
that carries trace context.
Pure standard library (json / logging); imports no PySide6. The
timer clock is injectable, so durations are deterministic in CI.
Headless API
from je_auto_control import (
CanonicalLogLine, bind_trace_context, JSONLogFormatter,
new_root_context,
)
line = CanonicalLogLine({"event": "run_suite"})
bind_trace_context(line, new_root_context())
with line.timer("execute"):
run()
line.add("ok", True).emit(logger.info) # one wide line per run
# structured logging with trace correlation:
handler.setFormatter(JSONLogFormatter())
CanonicalLogLine accumulates request-scoped fields (add / update),
times a block into {name}_ms via timer (injectable clock), and
render / emit the wide line as JSON. bind_trace_context attaches a
SpanContext’s trace_id / span_id. JSONLogFormatter is a
logging.Formatter that emits one JSON object per record including
trace_id / span_id and any extra= fields — the log-trace correlation
counterpart to trace_context.
Executor command
AC_canonical_log builds a canonical line from a fields object and returns
{line, json}. It is exposed as the MCP tool ac_canonical_log and as a
Script Builder command under Report.