agent-proxy: instrument the request path with OTel spans + structlog events (tracer/logger are declared but never called) #28
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Want
Make agent-proxy actually emit the per-request detail its obs layer only declares today.
app/obs.pywiresget_tracer()(OTLP HTTP exporter, off unlessPROXY_OTEL_EXPORTER_OTLP_ENDPOINTis set) andget_logger()(structlog JSON), but there are zerostart_as_current_spanand zerologger.*call sites on the request path - so a SigNoz sees no traces anddocker logsshows nothing per-request. Prometheus/metricsis already fully wired (24 points); this ticket adds the trace + structured-log channels so localhost high-detail inspection works.Ask
Instrument the request path end to end:
main.py(/v1/chat/completions,/v1/completions), with child spans wrapping the real stages: queue enqueue/wait (queue.py), each upstream attempt (upstream.py), response validation (resilience.py), and each retry / fallback / circuit transition (resilience.py). The causal chain (which backend, which attempt, why it fell back) is the whole point.gen_ai.*(request model,gen_ai.usage.input_tokens/output_tokens,response.finish_reasons) plusagentproxy.*(logical model, resolved backend, dialect, trust tier if present) per the design notes in agent-proxy#18. SetOTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental.loggerevent per backend attempt and per terminal outcome (ok / rejected / failed / truncation-avoided / validation-failure), carrying the same dims. These are the localhostdocker logs/Dozzle high-detail stream.Detail vs redaction
Full span/log detail (prompt/completion/tool payloads) is for a local OTLP backend only - the shared fleet SigNoz (
ser8:4318) has no ingest redaction. So: put bodies behind an explicit high-detail flag (e.g.PROXY_TRACE_BODIES=1, default OFF) so the default export is metadata-only and safe for any sink, and full bodies are an opt-in you enable when pointing at localhost. Document the flag.Coordination
upstream.py,analysis.py, andresilience.pyare being actively rewritten by in-flight runs: agent-proxy#3 (dialect adapter in upstream.py), #4 (intent-detection in analysis.py), #19 (reliability harness). Expect to integratemainand rebase onto their changes before landing - instrument the post-rebase shape, do not fight them.Acceptance
PROXY_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318, a request produces a trace whose span tree shows queue -> upstream attempt(s) -> validation -> outcome, with gen_ai.* token/finish attributes.docker logs agent-proxyshows a structured event per backend attempt and terminal outcome.Refs
🔒 Reserved by
ward agent --driver codex— containerengineer-codex-agent-proxy-28on hostkais-macbook-pro-2.localis carrying this issue (reserved 2026-07-02T09:31:24Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.— Codex, via
ward agentWARD-OUTCOME: done - added request-path spans and structured logs
The work stayed mostly mechanical once the request flow was mapped. The only friction was keeping the async span boundaries and the no-op path aligned without breaking the existing tests. Confidence is good, but the stream path still deserves a little real-world smoke testing with OTLP enabled.