Every gateway request is in the audit log as models.gateway.request, without prompt content. Request logs add a searchable row per request and, if you choose, the bodies, sealed under your organisation's key.
Turn request logs on
Request logs are off by default. Open Models > Request log settings, or:
curl -sS -X PUT "$KEYSTONE_URL/api/v1/models/logging" \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'Content-Type: application/json' \
-d '{"mode": "metadata", "retention_days": 30, "max_classification": "internal"}'
| Field | Values |
|---|---|
mode | off, metadata (one row per request) or full (metadata plus bodies) |
retention_days | 1 to 365 |
max_classification | The strictest classification whose bodies full keeps (default internal) |
Every field is required. Reading the settings needs models:view; changing them needs models:admin and is audited as models.logging.put. full needs the deployment's key management service (503 models.request_logs.unavailable otherwise).
What a row holds
One row per request, rewritten by each upstream attempt and ending with the outcome the caller got. Refusals are logged too, including those refused before the caller was resolved.
Fields include request_id, api, requested_model, route, model_key, status (completed, upstream_error, client_closed or refused), http_status, refusal_code, attempts, input_tokens, output_tokens, cost_micros, latency_ms, cache, stream, user_id or api_key_id, project_id, classification, prompt, context_request_id, client_id, client_app, has_bodies and body_note.
Bodies
In full mode the row also keeps the request as sent upstream after DLP (the redacted body, never the original) and the answer as the caller received it, each at most 2 MiB. Each body is sealed with AES-256-GCM under a data key wrapped by the organisation's key models-gateway-logs. Nothing is stored unsealed.
Bodies are never kept for a request in a regulated project, whatever max_classification says. When a body is not kept, body_note says why: classification, too_large, unavailable, seal_failed or not_scanned.
Read logs
Open Models > Request logs (under Monitor) or AI Gateway > Gateway requests.
| Route | Permission | Audit |
|---|---|---|
GET /api/v1/models/logs | models:view | models.request_log.list |
GET /api/v1/models/logs/{request_id} | models:view | models.request_log.get |
GET /api/v1/models/logs/{request_id}?include=bodies | models:admin | models.request_log.read_bodies, committed with the read |
GET /logs filters by from, to, user_id, model (answering model, requested model or route), status and context_request_id, pages with limit (1 to 200) and cursor, and returns newest first.
Rows older than the retention are deleted hourly by models.request_log_purge (schedule NI_AUTH_MODELS_REQUEST_LOG_PURGE_SCHEDULE, off disables it).
Attribute traffic
| Request header | Rule |
|---|---|
X-Keystone-Metadata | One JSON object, at most 8192 bytes and 16 keys. Keys match ^[a-z][a-z0-9_.-]{0,63}$; values are strings of at most 256 bytes. Keys starting with keystone. are reserved. |
X-Keystone-Tags | Up to 10 comma-separated tags matching ^[A-Za-z0-9][A-Za-z0-9_.:/@-]{0,63}$ |
X-Keystone-Client | name/version of the calling app, recorded as advisory |
A header that breaks a rule is refused with 400 invalid_request before anything is reserved. Metadata and tags are DLP-scanned at the request's classification, carried into usage events, the audit record and route conditions, and never sent to the provider. A gateway key's own metadata wins over the header's.
The OAuth client of the caller's token (client_id) is recorded as verified. X-Keystone-Client is recorded as advisory, because a client can send anything.
Token counting
POST /api/v1/models/gateway/v1/messages/count_tokens counts a request's input tokens. It is decided like a real request (access, DLP, guardrails, rate limits) and audited with operation: count_tokens. Models served through the Anthropic wire format are counted by their provider with the organisation's key; any other model, or a failed provider count, is answered with the gateway's estimate and "estimated": true. Nothing is generated and no budget is reserved.
Other views
| Console page | Shows |
|---|---|
| Models > Provider health | Probe results and circuit state per connection |
| Models > Model usage | Usage and spend from the gateway's usage events |
| AI Gateway > Gateway overview, Gateway costs | Traffic and FinOps views |
| AI Gateway > Gateway keys > key > Usage | Per-key analytics |
The organisation's model usage also appears in Insights. Request logs and usage events are separate from the audit log, which is described on Audit log.