Opt-in logging
Inference logging is off by default. With it off, the gateway writes no per-request row at all: it enforces your policy, forwards the request, and keeps nothing.
Switching it on gives you one row per proxied request. Metadata only — see zero data retention for why content cannot appear here even in principle.
vulnetix ai-firewall settings --logs # on
vulnetix ai-firewall settings --no-logs # off
Or the Usage tab of the dashboard. Requires a paid plan.
Check the current state:
vulnetix ai-firewall status
# Inference logging: on
Exactly what is recorded
The complete field list. There is nothing else.
| Field | What it is |
|---|---|
providerSlug | Which provider the request went to |
model | The model requested |
wire | Which request surface it arrived on — chat, responses, or messages |
decision | allow, block, redact, or flag |
blockedBy | The name of the rule that blocked it, if any |
violations | Which rules fired — names and types, never the matched content |
inspected | How many text segments the guardrails read |
statusCode | The HTTP status returned |
promptTokens / completionTokens | Token counts, when the provider reports them |
stream | Whether the response was streamed |
latencyMs | How long it took |
createdAt | When |
What is not recorded
- The prompt. Any part of it.
- The completion. Any part of it.
- The content that tripped a guardrail. A
flagrecords that a rule matched and which one — never what it matched. - Headers, tool definitions, tool arguments, or tool results.
The two fields worth understanding
inspected — proof the firewall actually looked
This is the number of text segments the guardrail engine read out of the request.
It exists to make one specific, nasty failure visible: a request that parses
cleanly but exposes nothing to inspect is a firewall screening nothing — and without
this number it looks exactly like a clean pass. Everything is green, every
dashboard says allow, and no rule is running against any text.
An inspected of 0 against a non-empty policy set is a bug, and it is the one
you most want to catch. It is the reason the field is there.
wire — which client this actually was
Which surface the request arrived on. Without it, a Codex inference is indistinguishable from a Claude Code one after the fact, and any per-client incident becomes impossible to reason about.
What you can do with it
- Tune your guardrails. Which rules fire, how often, and on which surface. This is how you run the flag → redact → block ladder with evidence rather than a guess.
- See which models are actually being used. Frequently, this is not the set anyone expected, and it is the input to a sensible model allowlist.
- Attribute cost. Token counts per model, per surface. Note: the firewall does no cost accounting itself and applies no markup — this is raw token counts, and your bill still comes from the provider.
- Investigate a block.
blockedByandviolationstell you exactly which rule refused a request and why, without exposing what was in it.
The trade-off, stated plainly
Because violations never record content, you cannot read the prompts your rules caught. You learn a rule fired forty times; you cannot see the forty prompts.
That makes tuning harder. It is a deliberate choice: the alternative is that enabling a guardrail creates a new datastore containing the most sensitive strings your organisation produces, which is precisely the thing you adopted a firewall to prevent.
Tune by reasoning about the pattern, not by reading the traffic. See tuning false positives.
Turning it off
vulnetix ai-firewall settings --no-logs
Takes effect on the next request. New rows stop being written immediately.
In policy as code
spec:
settings:
logsEnabled: true
See policy as code.
Related
- Zero data retention — why content cannot appear here.
- Rollout — what you use these logs for.
- Verify — proving traffic reaches the firewall.