M2.5.1: Structured application logger (structlog) #24

Closed
opened 2026-04-08 21:43:25 +00:00 by claude-code · 0 comments
Collaborator

Phase 2.5 — Logging & Cost Visibility, milestone 1.

Goal

A real, structured application logger across CLI, MCP server, and researcher. JSONL traces stay as-is (researcher audit trail); this is the parallel operational log for administrators.

Target sink eventually: OpenSearch (or similar). Format must be machine-ingestable from day one.

Backend

structlog with:

  • ConsoleRenderer for local/dev (colored, human-readable)
  • JSONRenderer for prod (newline-delimited JSON, OpenSearch-ready)
  • Toggle via MARCHWARDEN_LOG_FORMAT=json|console (default console if a TTY, else json)
  • Funnels stdlib logging (anthropic SDK, mcp SDK, httpx) through the same pipeline via structlog.stdlib

Scope

  • New module marchwarden/logging.py (~30 LOC) — one-time configure_logging() call
  • Named loggers per component:
    • marchwarden.cli
    • marchwarden.mcp
    • marchwarden.researcher.web
  • Levels: DEBUG / INFO / WARN / ERROR
  • MARCHWARDEN_LOG_LEVEL env var (default INFO); per-component overrides via MARCHWARDEN_LOG_LEVEL_<COMPONENT> (optional, only if cheap)
  • Output: stderr always (so MCP stdio stdout stays clean)
  • Optional rotating file at ~/.marchwarden/logs/marchwarden.log controlled by MARCHWARDEN_LOG_FILE=1
  • Context binding: at the top of each research() call, bind trace_id and researcher so every downstream log line carries them automatically

Conversion

Replace existing ad-hoc print calls and FastMCP defaults with structured log calls. Do NOT touch the JSONL trace logger — that's a separate concern.

Tests

  • Configure once, log a sample event in each renderer, assert JSON output has expected keys (event, level, timestamp, bound context)
  • Verify stdout stays untouched when logging fires

Out of scope

  • Cost ledger (M2.5.2)
  • marchwarden costs command (M2.5.3)
  • Shipping to OpenSearch (separate infra issue when we get there)

Branch

feat/structured-logging

Phase 2.5 — Logging & Cost Visibility, milestone 1. ## Goal A real, structured application logger across CLI, MCP server, and researcher. JSONL traces stay as-is (researcher audit trail); this is the parallel **operational** log for administrators. Target sink eventually: OpenSearch (or similar). Format must be machine-ingestable from day one. ## Backend **`structlog`** with: - `ConsoleRenderer` for local/dev (colored, human-readable) - `JSONRenderer` for prod (newline-delimited JSON, OpenSearch-ready) - Toggle via `MARCHWARDEN_LOG_FORMAT=json|console` (default `console` if a TTY, else `json`) - Funnels stdlib `logging` (anthropic SDK, mcp SDK, httpx) through the same pipeline via `structlog.stdlib` ## Scope - New module `marchwarden/logging.py` (~30 LOC) — one-time `configure_logging()` call - Named loggers per component: - `marchwarden.cli` - `marchwarden.mcp` - `marchwarden.researcher.web` - Levels: DEBUG / INFO / WARN / ERROR - `MARCHWARDEN_LOG_LEVEL` env var (default `INFO`); per-component overrides via `MARCHWARDEN_LOG_LEVEL_<COMPONENT>` (optional, only if cheap) - Output: stderr always (so MCP stdio stdout stays clean) - Optional rotating file at `~/.marchwarden/logs/marchwarden.log` controlled by `MARCHWARDEN_LOG_FILE=1` - **Context binding**: at the top of each `research()` call, bind `trace_id` and `researcher` so every downstream log line carries them automatically ## Conversion Replace existing ad-hoc `print` calls and FastMCP defaults with structured log calls. Do NOT touch the JSONL trace logger — that's a separate concern. ## Tests - Configure once, log a sample event in each renderer, assert JSON output has expected keys (`event`, `level`, `timestamp`, bound context) - Verify stdout stays untouched when logging fires ## Out of scope - Cost ledger (M2.5.2) - `marchwarden costs` command (M2.5.3) - Shipping to OpenSearch (separate infra issue when we get there) ## Branch `feat/structured-logging`
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: archeious/marchwarden#24
No description provided.