feat(observability): run trace tree, /metrics endpoint, hive trace CLI - #56
Conversation
- logging/trace.py: Span model + TraceBuilder deriving run -> agent ->
goal -> decision/tool from the run's JSONL logs (pure transform;
JSONL stays the source of truth). Deterministic span ids; uncorrelated
pre-existing logs attach to the agent span instead of being dropped.
- GET /runs/{id}/trace returns the span tree; GET /metrics exposes
Prometheus text (agents by status + latest-run counters), no new deps
- hive trace <run-id> renders the tree with Rich
- docs: rest-api endpoint table, cli-reference
Master plan A/PR2 (consumes A/PR1's goal/step correlation)
|
| Filename | Overview |
|---|---|
| src/hive/logging/trace.py | New TraceBuilder with deterministic span IDs, in_progress goal tracking, and segment sanitization; the step_index is None guard is dead code (model defaults to 0, not None), and goal IDs matching the d{i}/t{i} naming convention can collide with uncorrelated span IDs. |
| src/hive/server/routes/system.py | Two clean new endpoints: /runs/{id}/trace (404 on empty list) and /metrics (hand-rendered Prometheus text with correct gauge types and snapshot HELP text). |
| src/hive/cli/main.py | New hive trace command uses Rich to render the span tree; falls back to logs/ under cwd, consistent with other CLI commands. |
| tests/logging/test_trace.py | Good coverage: tree shape, open-goal in_progress, deterministic IDs, slash sanitization, and pre-correlation fallback. |
| tests/server/test_rest_api.py | Adds 404 test for unknown trace and basic Prometheus content-type + gauge line assertions. |
Sequence Diagram
sequenceDiagram
participant CLI as hive trace CLI
participant API as GET /runs/{id}/trace
participant Metrics as GET /metrics
participant TB as TraceBuilder
participant LR as LogReader
participant FS as JSONL Logs
CLI->>TB: build(run_id)
TB->>LR: get_run(run_id)
LR->>FS: read run.json
FS-->>LR: RunLog
LR-->>TB: "RunLog | None"
TB->>LR: get_agent_ids(run_id)
loop per agent
TB->>LR: get_agent_goals / decisions / tools
LR->>FS: read goals.jsonl, decisions.jsonl, tools.jsonl
FS-->>LR: records
LR-->>TB: "list[GoalLog|DecisionLog|ToolLog]"
end
TB-->>CLI: list[Span]
CLI->>CLI: render Rich tree
API->>TB: asyncio.to_thread(build, run_id)
TB-->>API: list[Span]
API-->>API: model_dump to list[dict]
Metrics->>LR: asyncio.to_thread(list_runs)
LR-->>Metrics: list[RunLog]
Metrics->>LR: asyncio.to_thread(get_summary, runs[0])
LR-->>Metrics: dict[str, Any]
Metrics-->>Metrics: render Prometheus text
Reviews (3): Last reviewed commit: "Update src/hive/logging/trace.py" | Re-trigger Greptile
- sanitize '/' in goal/agent ids when building span ids (a goal literally named 'g/d0' could collide with goal g's first decision span) - O(1) goal-span lookup via a goal_id -> Span map instead of an O(n) list scan per goal event - open goals report outcome 'in_progress' instead of staying 'generated' forever when a run crashes or is snapshotted mid-flight - /metrics HELP text marks per-run values as snapshots that reset each run (gauges, not counters) so scrapers don't apply rate()/increase() - tests for the collision and in-progress cases
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Summary
First observability surface over the structured run logs (master plan A/PR2, unblocked by the goal/step correlation fix that just merged in #55):
logging/trace.py--Spanmodel +TraceBuilderderiving a span tree (run -> agent -> goal -> decision/tool) from a run's JSONL logs. Pure data transform: the JSONL files stay the single source of truth, no new write path. Span ids are deterministic; decisions/tools without agoal_id(goal generation, pre-correlation logs) attach to the agent span instead of being dropped.GET /runs/{id}/trace-- the span tree as JSON (404 for unknown runs), built off the event loop viaasyncio.to_threadlike the other log endpoints.GET /metrics-- Prometheus text exposition (hand-rendered, no new dependency): agents by status from the store plus latest-run counters (goals generated/completed/abandoned, tool calls, tokens, cost).hive trace <run-id>-- renders the tree in the terminal with Rich (goal outcomes, decision token counts, tool success marks).Test plan
tests/logging/test_trace.py: tree shape, goal open/close + outcome annotation, deterministic ids, pre-correlation logs still build.tests/server/test_rest_api.py: trace 404,/metricscontent type + gauge lines.Docs: endpoint table in
rest-api.md,hive traceincli-reference.md.