Router Access Log Fields Reference
Kthena emits one access-log entry after each /v1/* inference request.
Requests routed through Gateway API on other paths currently do not emit an
access-log entry. Each recorded entry contains the HTTP result, routing
selection, token counts, timing checkpoints, and any router error captured
during processing.
Formats and defaults
Access logs support two formats:
textis the current Helm default and preserves existing installations.jsonis recommended for log aggregation and field-based queries, but must be enabled explicitly.
The text representation is a single line with this shape:
[timestamp] "METHOD /path PROTOCOL" status_code [error=type:message] [model_name=name] [model_route=route] [model_server=server] [selected_pod=pod] [request_id=id] [gateway=gateway] [http_route=route] [inference_pool=pool] [tokens=input/output] timings=totalms(request+upstream+response)
Fields in square brackets are omitted when no value is available. JSON uses the names in the tables below.
HTTP fields
| Field | Type | Presence | Description | Example |
|---|---|---|---|---|
timestamp | RFC3339 timestamp | Always | Time the router received the request | 2026-01-09T14:35:22.147Z |
method | String | Always | HTTP method | POST |
path | String | Always | URL path only; the query string is not included | /v1/chat/completions |
protocol | String | Always | HTTP protocol reported by Go | HTTP/1.1 |
status_code | Integer | Always | Final HTTP response status | 200 |
Error fields
The error object is omitted from JSON when the router did not record an
error. In text logs it appears immediately after the status code.
| Field | Type | Description | Example |
|---|---|---|---|
error.type | String | Stable error category assigned by the router | pod_discovery |
error.message | String | Diagnostic message for this failure | no available pods for model server: default/llama2-server |
Current router error categories are:
| Error type | Failure area |
|---|---|
request_parsing | Request body or required model field could not be parsed |
prompt_parsing | Prompt extraction failed |
input_rate_limit | Input-token limit was exceeded |
output_rate_limit | Output-token limit was exceeded |
rate_limit | General request/token rate limit was exceeded |
model_server_matching | No matching ModelServer could be selected |
pod_discovery | Backend pod lookup failed or returned no available pods |
inference_pool_selection | A matched HTTPRoute had no eligible InferencePool backend |
inference_pool_discovery | The selected InferencePool could not be found |
port_discovery | An InferencePool had no usable target port |
route_not_found | Neither ModelRoute nor HTTPRoute routing matched |
scheduling | Queue admission or backend scheduling failed |
proxy | Forwarding to the selected backend failed |
An HTTP status is not uniquely determined by error.type; consult
status_code for the actual result.
Model and routing fields
| Field | Type | Presence | Description | Example |
|---|---|---|---|---|
model_name | String | Always in JSON; may be empty when parsing fails | Model requested by the client | llama2-7b |
model_route | String | When selected | Namespaced ModelRoute | default/llama2-route-v1 |
model_server | String | When selected | Namespaced ModelServer | default/llama2-server |
selected_pod | String | When selected | Backend pod name | llama2-deployment-5f7b8c9d-xk2p4 |
request_id | String | Normally present | Incoming x-request-id, or an ID generated by the access-log middleware | 550e8400-e29b-41d4-a716-446655440000 |
gateway | String | Gateway API requests | Namespaced Gateway | default/inference-gateway |
http_route | String | HTTPRoute requests | Namespaced HTTPRoute | default/inference-route |
inference_pool | String | Inference Extension requests | Namespaced InferencePool | default/llama2-pool |
Token fields
| Field | Type | Presence | Description | Example |
|---|---|---|---|---|
input_tokens | Integer | JSON omits zero | Prompt-token count calculated by the router | 150 |
output_tokens | Integer | JSON omits zero | Completion-token count parsed from the backend response when available | 75 |
Text output includes tokens=input/output when either count is nonzero.
Timing fields
All timing values are integer milliseconds.
| Field | Type | Description | Example |
|---|---|---|---|
duration_total | Integer | End-to-end time from receipt until access-log finalization | 2350 |
duration_request_processing | Integer | Initial router parsing and tokenization phase | 45 |
duration_upstream_processing | Integer | Marked backend-proxy phase | 2180 |
duration_response_processing | Integer | Marked response-processing phase | 5 |
There is no duration_queue field and no access-log field uses an _ms
suffix. duration_total is authoritative. The phase fields are independently
rounded checkpoints and may not sum to the total, including when rate limiting,
routing, scheduling, or queue time falls between marked phases.
Examples
Successful JSON entry
{
"timestamp": "2026-01-09T14:35:22.147Z",
"method": "POST",
"path": "/v1/chat/completions",
"protocol": "HTTP/1.1",
"status_code": 200,
"model_name": "llama2-7b",
"model_route": "default/llama2-route-v1",
"model_server": "default/llama2-server",
"selected_pod": "llama2-deployment-5f7b8c9d-xk2p4",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"input_tokens": 150,
"output_tokens": 75,
"duration_total": 2350,
"duration_request_processing": 45,
"duration_upstream_processing": 2180,
"duration_response_processing": 5
}
Failed JSON entry
{
"timestamp": "2026-01-09T14:35:28.456Z",
"method": "POST",
"path": "/v1/chat/completions",
"protocol": "HTTP/1.1",
"status_code": 503,
"error": {
"type": "pod_discovery",
"message": "no available pods for model server: default/llama2-server"
},
"model_name": "llama2-7b",
"request_id": "660e8400-e29b-41d4-a716-446655440001",
"input_tokens": 200,
"duration_total": 51,
"duration_request_processing": 4,
"duration_upstream_processing": 47,
"duration_response_processing": 0
}
Text entry
[2026-01-09T14:35:22.147Z] "POST /v1/chat/completions HTTP/1.1" 200 model_name=llama2-7b model_route=default/llama2-route-v1 model_server=default/llama2-server selected_pod=llama2-deployment-5f7b8c9d-xk2p4 request_id=550e8400-e29b-41d4-a716-446655440000 tokens=150/75 timings=2350ms(45+2180+5)
Helm configuration
The root chart uses the following values. The defaults shown here preserve the current text-format behavior:
networking:
kthenaRouter:
accessLog:
enabled: true
format: text
output: stdout
Set format: json explicitly when a structured log pipeline requires JSON.
For the standalone networking subchart, omit the networking prefix:
kthenaRouter:
accessLog:
enabled: true
format: json
output: stdout
Environment variables
The deployment maps Helm values to these router environment variables:
| Variable | Description | Helm default | Accepted values |
|---|---|---|---|
ACCESS_LOG_ENABLED | Enable access logging | true | Values accepted by Go's boolean parser |
ACCESS_LOG_FORMAT | Output format | text | text, json |
ACCESS_LOG_OUTPUT | Destination | stdout | stdout, stderr, or a file path |
Prefer stdout for Kubernetes workloads. A file path writes inside the router
container and requires a mounted volume plus a separate collection strategy.