judgevet.adapters.inbound.logs

Status: draft.

judgevet.adapters.inbound.logs

Structured logging with built-in field contracts and scoped caller correlation.

Logs are diagnostics, not evidence. Telemetry is evidence: append-only, raw responses, every row stamped (ADR-0006). A verdict never reads a log line. The two carry the same ids, so they join.

Logging is a cross-cutting concern, not a port. The composition root calls configure once, and adapters call structlog.get_logger() directly. The domain may not import structlog at all (ADR-0001).

Every line goes to stderr, so --json output on stdout keeps piping. A TTY gets the console renderer, anything else gets JSON lines. A traceback prints its frames without their locals in both formats, so a secret held in a failing frame never reaches the line.

Attributes:

Name Type Description
LogSettings

The log branch of the root Settings.

REDACTED

What a masked value is replaced with.

SECRET_KEYS

Field names whose values never reach the output.

Examples:

configure(LogSettings(format="json", level="debug"))
bind_invocation(command="jev call", run_id=new_run_id())
structlog.get_logger().info("call.start", questions=5)
See Also

LogSettings

Bases: BaseModel

How the lines are rendered and which ones are kept.

Attributes:

Name Type Description
format str

auto, json or console. Default auto.

level str

debug, info, warning, error or critical. Default info.

Examples:

assert LogSettings().format == "auto"
assert LogSettings(level="debug").level == "debug"

bind_command(command)

Name the command, keeping this invocation's run_id.

A sub-application calls this from its own callback, where the sub-command's name is finally known.

Parameters:

Name Type Description Default
command str

For example jev call.

required

Examples:

bind_command("jev call")

bind_invocation(command, run_id)

Bind what every line of this invocation carries.

Parameters:

Name Type Description Default
command str

For example jev.

required
run_id str

From new_run_id.

required

Examples:

bind_invocation("jev", new_run_id())

configure(settings, stream=None)

Configure rendering and built-in field filtering at the composition root.

Lines go to stream, which defaults to stderr so --json output on stdout keeps piping. Calling it again replaces the configuration, which is what a test needs.

A traceback renders without frame locals in both formats. The JSON path transforms the exception into a dict before redact runs, so a PEM in an exception message is masked too.

Parameters:

Name Type Description Default
settings LogSettings

Format and level.

required
stream Any

Where to write. Default stderr.

None

Examples:

configure(LogSettings(format="json"))

configure_mcp_logging()

Route SDK warnings and errors through the configured safe stderr renderer.

The SDK's exception logger otherwise writes raw exception text to stderr. Only the MCP composition root calls this; library imports change nothing.

new_run_id()

Identify one CLI invocation, so its lines join to each other.

Returns:

Type Description
str

Twelve hex characters.

Examples:

assert len(new_run_id()) == 12

redact(_logger, _method, event_dict)

Masks by field name at any depth of a dict, a list, a tuple or a set. Masks any string carrying a PEM header, whatever its field is called. Renders any other object as its type name. Passes the exc_info tuple untouched: the renderer consumes it, and the frames it prints carry no locals.

Parameters:

Name Type Description Default
_logger Any

The wrapped logger. Unused.

required
_method str

The level method name. Unused.

required
event_dict dict[str, Any]

The event being rendered.

required

Returns:

Type Description
dict[str, Any]

The event with secrets replaced by REDACTED.

Examples:

assert redact(None, "info", {"api_key": "k"})["api_key"] == "***"

wants_json(settings, stream)

Decide the renderer: JSON lines unless a terminal is watching.

json and console force the choice. auto renders for a person at a TTY and for a machine everywhere else.

Parameters:

Name Type Description Default
settings LogSettings

The log settings.

required
stream Any

Where lines are written.

required

Returns:

Type Description
bool

True for JSON lines, False for the console renderer.

Examples:

assert wants_json(LogSettings(format="json"), sys.stderr)