Skip to content

Commit 80c3da2

Browse files
committed
docs(adr): Specify agentic logging
why: The logging study surfaced a clear project contract: logs should be structured, trace-linked status records that aid local agentic loops without leaking prompt-history content or changing user-visible output. what: - Add ADR 0009 for sparse structured logging at critical boundaries. - Require OTel-oriented logs to stay inside active project spans. - Document privacy, cardinality, and verification constraints.
1 parent 28582b5 commit 80c3da2

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
(adr-agentic-structured-logging)=
2+
3+
# ADR 0009: Agentic structured logging
4+
5+
## Status
6+
7+
Accepted.
8+
9+
## Context
10+
11+
ADR 0008 established local OpenTelemetry as an opt-in observability surface for
12+
agentgrep. It also requires exported logs to be trace-linked and sanitized
13+
because agentgrep reads local prompt-history stores.
14+
15+
The next gap is usefulness. A trace tree can show that work happened, but
16+
agentic debugging loops often need a small stream of structured status records:
17+
which surface ran, which boundary completed, how many sources or results were
18+
involved, whether a handoff failed, and which trace to open next.
19+
20+
The logging systems studied for this decision repeat a few durable patterns.
21+
Operational status is separated from result payloads. Sensitive or
22+
security-adjacent decisions use typed, stable fields rather than prose blobs.
23+
OpenTelemetry treats trace and span identifiers as first-class log correlation
24+
fields. Those patterns fit agentgrep if logs stay sparse, schema-oriented, and
25+
content-free.
26+
27+
## Decision
28+
29+
agentgrep uses structured Python logging as a low-volume status stream for
30+
critical operation boundaries. Logs complement spans and metrics; they do not
31+
replace them and they do not carry search result content.
32+
33+
Critical boundaries include CLI command lifecycle, MCP request/tool lifecycle,
34+
TUI session and worker lifecycle, engine search and find lifecycle, profiling
35+
and benchmark runs, OTel acceptance smoke work, and sensitive decisions such as
36+
environment/config path handling or MCP argument summarization.
37+
38+
Each telemetry-oriented log record should carry stable `agentgrep_*` fields.
39+
The preferred base fields are:
40+
41+
- `agentgrep_surface`
42+
- `agentgrep_operation` or the established surface-specific operation key
43+
- `agentgrep_outcome`
44+
- safe counts such as source, planned-source, result, record, or batch counts
45+
- elapsed duration when the surrounding boundary has an obvious timer
46+
- bounded enums such as scope, strategy, method, tool, adapter, or error type
47+
48+
Logs are emitted from inside active project spans when they are meant for OTel.
49+
That keeps Loki records correlated with Tempo traces and avoids orphan log
50+
events. Library code still does not configure handlers, levels, console output,
51+
or exporters; `agentgrep._telemetry` owns opt-in export.
52+
53+
Telemetry logs describe operation shape, not local content. They must not
54+
record raw prompts, query terms, raw argv, raw MCP arguments, environment
55+
values, file contents, full exception text that may contain content, or local
56+
absolute paths. Use booleans, counts, enums, redacted path metadata, and
57+
length/digest summaries instead.
58+
59+
High-volume detail belongs in spans, metrics, profiles, or bounded aggregate
60+
fields. Per-record, per-line, per-keypress, render-frame, and hot-loop logs are
61+
not accepted signal.
62+
63+
## Consequences
64+
65+
### Positive
66+
67+
- Loki becomes useful for local agentic loops without requiring operators to
68+
reconstruct every status transition from spans.
69+
- Logs link directly to traces, so a Grafana drilldown can move from a status
70+
event to the exact CLI, MCP, TUI, or engine execution.
71+
- Normal users still see no logging output unless an application configures it.
72+
- Prompt-history content and local machine paths stay out of exported logs.
73+
74+
### Tradeoffs
75+
76+
- Boundary logs add maintenance surface because field names become
77+
compatibility-sensitive once dashboards or alert queries rely on them.
78+
- Some spans and logs will describe the same operation. This duplication is
79+
accepted when the log is the searchable status record and the span is the
80+
timing/trace context.
81+
- Sparse logging means deep per-record investigation still requires local
82+
reproduction, targeted debug logs, or a profiling artifact.
83+
84+
### Rejected options
85+
86+
- Logging every parsed record or match: rejected because it risks content
87+
leakage, high cardinality, and hot-loop overhead.
88+
- Exporting logs outside active spans: rejected because unlinked Loki events
89+
are hard to use and were explicitly disallowed by ADR 0008.
90+
- Console logging for local development by default: rejected because CLI and
91+
MCP stdout/stderr are public behavior.
92+
- Free-form message-only logs: rejected because agentic loops need filterable
93+
fields and stable dashboards.
94+
95+
## Tests and verification
96+
97+
Unit tests for new telemetry logs should assert on structured attributes, not
98+
formatted text. Use the in-memory telemetry backend when trace/span linkage is
99+
part of the contract, and use `caplog.records` for ordinary logging schema
100+
tests.
101+
102+
Live verification belongs in `just otel-acceptance`. The acceptance check must
103+
continue to prove that current-run Loki logs have trace and span identifiers.

docs/dev/adr/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ multiple adapters or public payloads.
1616
0006-public-cli-mcp-surface-contract
1717
0007-query-language-comparison-and-full-queryability
1818
0008-opentelemetry-local-observability
19+
0009-agentic-structured-logging
1920
```

0 commit comments

Comments
 (0)