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 |
|
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
- judgevet.adapters.inbound.cli: Calls
configureonce.
LogSettings
Bases: BaseModel
How the lines are rendered and which ones are kept.
Attributes:
| Name | Type | Description |
|---|---|---|
format |
str
|
|
level |
str
|
|
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 |
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 |
required |
run_id
|
str
|
From |
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 |
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)