---
title: "Access log operators"
url: "/reference/observability/access-log-operators/"
kind: "reference"
summary: "The complete table of command operators accepted in Arion access-log and header format strings."
---

> Arion site index: [/llms.txt](/llms.txt)

# Access log operators

The complete table of command operators accepted in Arion access-log and header format strings.

This page lists every command operator Arion's formatter accepts in an access-log `text_format` (and in [header mutation values](@/reference/resources/routes.md#header-mutations)).

## Syntax

Operators are written `%NAME%`; `%REQ(...)%` and `%RESP(...)%` take a header name or pseudo-header argument in parentheses, and `%%` produces a literal percent sign. Format strings are validated at configuration load: a name that is not a supported operator (or a registered custom operator) is rejected, so a bad format stops Arion from starting or the xDS update from being accepted. Envoy operators that exist but are not implemented (for example `%DYNAMIC_METADATA%` or the TLS certificate operators) are rejected the same way, and no operator takes a formatting argument (`%START_TIME(...)%` is invalid). An operator with no value for the current log renders as `-`, unless the format sets `omit_empty_values: true`, in which case it renders as nothing.

When no `text_format` is given, the default is Envoy's default HTTP log format:

```text
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"
```

Access logs attach in three places: the HTTP connection manager (one line per request), the TCP proxy (one line per connection) and the listener (one line per connection, with whole-connection totals). The Notes column says where an operator produces a value; anywhere else it renders `-`.

## Request

| Operator | Value | Notes |
|---|---|---|
| `%REQ(:METHOD)%` | Request method | HTTP only. |
| `%REQ(:PATH)%` | Request path | HTTP only. |
| `%REQ(:SCHEME)%` | Request scheme | HTTP only. |
| `%REQ(:AUTHORITY)%` | Request authority (Host) | HTTP only. |
| `%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%` | `x-envoy-original-path` header, falling back to the path | HTTP only. The `?` fallback form is supported only for this pair. |
| `%REQ(<HEADER>)%` | Value of the named request header | HTTP only. |
| `%REQUEST_HEADERS_BYTES%` | Size of the request headers in bytes | HTTP only. |
| `%PROTOCOL%` | Downstream HTTP protocol | HTTP only. |
| `%UNIQUE_ID%` | Request id; reuses a valid `x-request-id`, otherwise generates one | HTTP only. |
| `%TRACE_ID%` | Trace id of the request span | HTTP only; requires tracing. |

## Response

| Operator | Value | Notes |
|---|---|---|
| `%RESP(:STATUS)%` | Response status code | HTTP only. |
| `%RESP(<HEADER>)%` | Value of the named response header | HTTP only. |
| `%RESPONSE_CODE%` | Response status code | HTTP only. |
| `%RESPONSE_CODE_DETAILS%` | Why the response code was sent | HTTP and TCP proxy. |
| `%RESPONSE_HEADERS_BYTES%` | Size of the response headers in bytes | HTTP only. |
| `%RESPONSE_FLAGS%` | Short response/connection failure flags | HTTP and TCP proxy. |
| `%RESPONSE_FLAGS_LONG%` | Long (spelled-out) response flags | HTTP and TCP proxy. |

## Time and size

| Operator | Value | Notes |
|---|---|---|
| `%START_TIME%` | Request (or connection) start time | Everywhere. No strftime argument. |
| `%DURATION%` | Total duration in milliseconds | Everywhere; whole connection at listener/TCP level. |
| `%REQUEST_DURATION%` | Time to receive the full request from downstream (ms) | HTTP only. |
| `%REQUEST_TX_DURATION%` | Time until the full request was sent upstream (ms) | HTTP only. |
| `%RESPONSE_DURATION%` | Time until the first upstream response byte (ms) | HTTP only. `%TIME_TO_FIRST_BYTE%` is an alias. |
| `%RESPONSE_TX_DURATION%` | Time spent sending the response downstream (ms) | HTTP only. |
| `%BYTES_RECEIVED%` | Body bytes received (HTTP) or raw bytes received (listener/TCP) | Everywhere. |
| `%BYTES_SENT%` | Body bytes sent (HTTP) or raw bytes sent (listener/TCP) | Everywhere. |
| `%DOWNSTREAM_WIRE_BYTES_RECEIVED%` | Bytes received on the wire, including headers and TLS overhead | Everywhere. |
| `%DOWNSTREAM_WIRE_BYTES_SENT%` | Bytes sent on the wire, including headers and TLS overhead | Everywhere. |

## Connection

| Operator | Value | Notes |
|---|---|---|
| `%DOWNSTREAM_REMOTE_ADDRESS%` | Client address with port | Everywhere. |
| `%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%` | Client address | Everywhere. |
| `%DOWNSTREAM_REMOTE_PORT%` | Client port | Everywhere. |
| `%DOWNSTREAM_LOCAL_ADDRESS%` | Local (listener) address with port | Everywhere. |
| `%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%` | Local address | Everywhere. |
| `%DOWNSTREAM_LOCAL_PORT%` | Local port | Everywhere. |
| `%CONNECTION_ID%` | Downstream connection id | Everywhere. |
| `%CONNECTION_TERMINATION_DETAILS%` | Why the connection was closed | Everywhere. |
| `%REQUESTED_SERVER_NAME%` | TLS SNI value | HTTP only; `-` on plaintext connections. |
| `%ROUTE_NAME%` | Name of the matched route | HTTP only. |

## Upstream

| Operator | Value | Notes |
|---|---|---|
| `%UPSTREAM_HOST%` | Selected upstream endpoint address | HTTP and TCP proxy. |
| `%UPSTREAM_HOST_NAME%` | Upstream host name | HTTP only; currently identical to `%UPSTREAM_HOST%`. |
| `%UPSTREAM_HOST_NAME_WITHOUT_PORT%` | Upstream host name without port | HTTP only. |
| `%UPSTREAM_CLUSTER%` | Name of the upstream cluster | HTTP and TCP proxy. |
| `%UPSTREAM_CLUSTER_RAW%` | Cluster name (identical to `%UPSTREAM_CLUSTER%`; `alt_stat_name` is not supported) | HTTP and TCP proxy. |
| `%UPSTREAM_PROTOCOL%` | HTTP protocol used upstream | HTTP only. |
| `%UPSTREAM_TRANSPORT_FAILURE_REASON%` | Why the upstream connection failed | HTTP and TCP proxy. |
| `%UPSTREAM_LOCAL_ADDRESS%` | Local address of the upstream connection (with port) | TCP proxy only. |
| `%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%` | Local address of the upstream connection | TCP proxy only. |
| `%UPSTREAM_LOCAL_PORT%` | Local port of the upstream connection | TCP proxy only. |
| `%UPSTREAM_REMOTE_ADDRESS%` | Upstream endpoint address (with port) | TCP proxy only. |
| `%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%` | Upstream endpoint address | TCP proxy only. |
| `%UPSTREAM_REMOTE_PORT%` | Upstream endpoint port | TCP proxy only. |
| `%UPSTREAM_CONNECTION_ID%` | Upstream connection id | TCP proxy only. |

## Custom operators

Names registered under the top-level `access_logging.custom_operators` list become valid placeholders (`%user_id%`). Their values arrive at runtime as base64-encoded JSON carried in configurable hook headers; unpopulated custom operators render `-`. See [access logs](@/docs/observe/access-logs.md) for the hook configuration.

```yaml,name=arion.yaml,arion=fragment
access_logging:
  incoming_request_header: "x-arion-metadata"
  custom_operators: ["user_id", "session_id"]
```
