Skip to content

feat: unify access logging across both engines with stream correlation - #5

Merged
achetronic merged 2 commits into
masterfrom
feat/unified-access-log
Jul 14, 2026
Merged

feat: unify access logging across both engines with stream correlation#5
achetronic merged 2 commits into
masterfrom
feat/unified-access-log

Conversation

@achetronic

@achetronic achetronic commented Jul 14, 2026

Copy link
Copy Markdown
Owner

The policy's logging block now applies to both engines, and every log line of a request can be correlated.

  • The extProc engine now writes access logs. Until now only the extAuthz engine honored the logging block; traffic flowing through extProc left no record of what actually reached it. It now logs one access record per phase message at INFO, with the same exclusion, redaction and body rules the extAuthz access log already follows. Nothing changes in the extAuthz output.

  • Every line of a request can be correlated. All records produced for one HTTP request share a stream_id, and when the request carries an x-request-id header its value is promoted to a request_id field, so a request can be followed across the validator, Envoy and the upstream with a single filter.

extProc access           phase=requestHeaders   stream_id=31ce6daeede44919 request_id=envoy-req-42
extProc phase evaluated  phase=requestHeaders   stream_id=31ce6daeede44919
extProc access           phase=responseHeaders  stream_id=31ce6daeede44919 request_id=envoy-req-42

The logging block of the policy was only honored by the extAuthz HTTP
server; the extProc gRPC engine never logged request or response data,
leaving operators blind to what actually reaches it.

- Extract the access-log rendering (exclude/redact/mask/logBody) from
  httpserver into a shared internal/accesslog package. RequestAttrs is
  the former accessLogAttrs, byte-for-byte; ResponseAttrs is new and
  applies the same rules to response status, headers and body. No
  behavior change for extAuthz.
- The extProc engine now emits one 'extProc access' record at INFO for
  every phase message Envoy sends, with the data known at that point.
  What reaches the engine (which phases, whether bodies are streamed)
  remains a deployment concern of the Envoy processing_mode.
- Correlate everything: a per-stream stream_id (Envoy opens one
  ext_proc stream per HTTP request) is attached to all access,
  mutation and overflow records of a request, and x-request-id is
  promoted to a top-level request_id field when present.

Documented in POLICY_DSL.md and recorded as ADR D-024.
- Overflow WARN records carry the stream_id of their stream (canary:
  fails if the field is dropped).
- Overflow under global dry-run returns CONTINUE instead of an
  immediate 500, for both request and response bodies, and still logs
  the overflow with dry_run=true.
- A stream processed before any policy is loaded answers CONTINUE and
  emits no access record.
- Unknown phase messages (trailers) fall through to a CONTINUE.
- extractClientIP table: XFF single/list, X-Real-Ip fallback, empty.
- ResponseAttrs tolerates a nil response; redacted queries leave
  bare pairs without '=' untouched.
@achetronic achetronic self-assigned this Jul 14, 2026
@achetronic achetronic added the bug Something isn't working label Jul 14, 2026
@achetronic
achetronic merged commit bf5a75d into master Jul 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant