> ## Documentation Index
> Fetch the complete documentation index at: https://tyk.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Gateway Access Logs

> Learn how to configure Tyk Gateway to generate API access logs

## Introduction

An Access Log is a single log line written at `info` severity to `stderr` for every request Tyk Gateway handles, giving you a lightweight, real-time record of individual requests. This is a different mechanism from an [API Traffic Log](/docs/api-management/logs/traffic-logs), which also records individual requests but is written to Redis and processed asynchronously by Tyk Pump, carrying richer detail as a result.

Access Logs are generated by the same logger as Tyk Gateway's Application Log, so their severity, format, and third-party output are all controlled by the same shared settings:

* **verbosity**: which severity levels are written (must be `info` or `debug` for Access Logs to be recorded at all)
* **format**: the structure and timestamp style of each entry
* **log output**: where logs are sent, for example to a third-party aggregator

See [Configuring Application and Access Logs](/docs/api-management/logs#configuring-application-and-access-logs) for details of these and how to configure them.

Access Logs have two additional settings of their own, covered below: whether they're generated at all ([Enabling Access Logs](#enabling-access-logs)), and which fields they include ([Access Log Content](#access-log-content)).

## Availability

| Component   | Version                                                                                | Edition                |
| :---------- | :------------------------------------------------------------------------------------- | :--------------------- |
| Tyk Gateway | Available since [v5.8.0](/docs/developer-support/release-notes/gateway#5-8-0-release-notes) | Community & Enterprise |

<Note>
  Access Logs are not available on Tyk Cloud.
</Note>

## Enabling Access Logs

Access Logs are disabled by default. Set `access_logs.enabled` to `true` to turn them on:

<Tabs>
  <Tab title="Configuration File">
    Configuration using `tyk.conf`:

    ```json theme={null}
    {
        "access_logs": {
            "enabled": true
        }
    }
    ```
  </Tab>

  <Tab title="Environment Variables">
    Configuration using environment variables:

    ```
    TYK_GW_ACCESSLOGS_ENABLED=true
    ```
  </Tab>
</Tabs>

## Access Log Content

Each Access Log entry contains:

* timestamp
* the log severity (always `info`)
* `prefix`, always set to `access-log`; this identifies the entry as an Access Log, since Application Log entries are written to the same output but use other `prefix` values.
* a configurable list of key-value pairs giving details of the request (for example API ID or HTTP response status code)

For example:

```
time="2025-01-29T08:27:09Z" level=info api_id=b1a41c9a89984ffd7bb7d4e3c6844ded api_key=00000000 api_name=httpbin api_type=oas client_ip="::1" host="localhost:8080" latency_gateway=1 latency_total=62 method=GET org_id=678e6771247d80fd2c435bf3 original_path=/get path=/get prefix=access-log protocol=HTTP/1.1 remote_addr="[::1]:63251" status=200 trace_id=4bf92f3577b34da6a3ce929d0e0e4736 upstream_addr="http://httpbin.org/get" upstream_latency=61 user_agent=PostmanRuntime/7.43.0
```

The keys that will be included in the logs are configured using an [access log template](#access-log-templates). If no template is configured, then all available fields will be included in each log entry. The `prefix` field is always included, whether or not a template is configured.

The full list of available fields that can be included in an access log is [here](#access-log-field-reference).

<Note>
  Field order is predictable, not arbitrary: `time` and `level` always come first, followed by every other field in alphabetical order.
</Note>

### Access Log Templates

You can define an access log template to reduce the size of the access log by including only a subset of the available fields. This is a simple list of field names declared in the Tyk Gateway configuration as a `template` array within the `access_logs` object.

For example:

<Tabs>
  <Tab title="Configuration File">
    Configuration using `tyk.conf`

    ```json theme={null}
    {
        "access_logs": {
            "enabled": true,
            "template": [
                "api_key",
                "remote_addr",
                "upstream_addr"
            ]
        }
    }
    ```
  </Tab>

  <Tab title="Environment Variables">
    Configuration using environment variables:

    ```
    TYK_GW_ACCESSLOGS_ENABLED=true
    TYK_GW_ACCESSLOGS_TEMPLATE="api_key,remote_addr,upstream_addr"
    ```
  </Tab>
</Tabs>

Output:

```
time="2025-01-29T08:27:48Z" level=info api_key=00000000 prefix=access-log remote_addr="[::1]:63270" upstream_addr="http://httpbin.org/get"
```

Only the three templated fields appear, plus `prefix`, which is always included regardless of the template.

### MCP-Specific Fields

When the log is generated for a request to an MCP Proxy, MCP-specific fields are added to the access log:

* [`mcp_method`](#param-mcp-method)
* [`mcp_primitive_type`](#param-mcp-primitive-type)
* [`mcp_primitive_name`](#param-mcp-primitive-name)
* [`mcp_error_code`](#param-mcp-error-code)

These fields are omitted when empty, so non-MCP logs are unaffected.

**Examples**

<AccordionGroup>
  <Accordion title="MCP tools/call request (success)">
    When an AI client calls a tool via an MCP Proxy:

    ```
    time="2025-04-07T10:15:30Z" level=info api_id=mcp-weather-api api_name=weather-mcp api_type=mcp
      latency_total=143 mcp_method=tools/call
      mcp_primitive_name=get_current_weather mcp_primitive_type=tool
      method=POST path=/mcp prefix=access-log status=200
    ```

    Key fields:

    * `api_type=mcp` identifies this as an MCP Proxy request.
    * `mcp_method=tools/call` indicates the JSON-RPC method invoked.
    * `mcp_primitive_type=tool` and `mcp_primitive_name=get_current_weather` identify the specific tool that was called.
  </Accordion>

  <Accordion title="MCP tools/call request (error)">
    When the upstream MCP server returns a JSON-RPC error:

    ```
    time="2025-04-07T10:16:02Z" level=info api_id=mcp-weather-api api_name=weather-mcp api_type=mcp
      latency_total=38 mcp_error_code=-32602 mcp_method=tools/call
      mcp_primitive_name=get_forecast mcp_primitive_type=tool
      method=POST path=/mcp prefix=access-log status=200
    ```

    Note that JSON-RPC errors are typically returned with HTTP 200 (as per the JSON-RPC spec). The `mcp_error_code` field identifies the error, and `response_flag` will reflect the gateway classification.
  </Accordion>
</AccordionGroup>

### Access Log Field Reference

<ParamField path="api_id">
  ID of the requested API definition. Present whenever the request matched an API.
</ParamField>

<ParamField path="api_key">
  Obfuscated or hashed API key used in the request.
</ParamField>

<ParamField path="api_name">
  Name of the requested API definition. Present whenever the request matched an API.
</ParamField>

<ParamField path="api_type">
  API type classification. One of `mcp`, `graphql`, `oas`, or `classic`. Always present.
</ParamField>

<ParamField path="circuit_breaker_state">
  Circuit breaker state (for example, `OPEN`), only present on circuit breaker errors.
</ParamField>

<ParamField path="client_ip">
  IP address of the client making the request.
</ParamField>

<ParamField path="error_source">
  Gateway component that generated the error, only present on error requests.
</ParamField>

<ParamField path="error_target">
  Upstream address being accessed, only present on upstream or proxy errors.
</ParamField>

<ParamField path="host">
  Hostname of the request.
</ParamField>

<ParamField path="latency_gateway">
  Time spent in Tyk Gateway's own processing, separate from the upstream round trip.
</ParamField>

<ParamField path="latency_total">
  Total time taken to process the request, including upstream latency and additional gateway processing.
</ParamField>

<ParamField path="mcp_error_code">
  JSON-RPC error code when the MCP request fails (for example, `-32001` for Authentication required, `-32002` for Access denied). Only present when an MCP error occurs.
</ParamField>

<ParamField path="mcp_method">
  JSON-RPC method called on an MCP Proxy (for example, `tools/call`, `initialize`, `resources/read`). Only present on MCP Proxy requests.
</ParamField>

<ParamField path="mcp_primitive_name">
  Name of the MCP tool, resource, or prompt that was invoked. Only present on MCP Proxy requests.
</ParamField>

<ParamField path="mcp_primitive_type">
  MCP primitive type invoked: `tool`, `resource`, or `prompt`. Only present on MCP Proxy requests.
</ParamField>

<ParamField path="method">
  HTTP method used in the request (for example, GET or POST).
</ParamField>

<ParamField path="org_id">
  Organisation ID of the requested API definition. Present whenever the request matched an API.
</ParamField>

<ParamField path="original_path">
  The client's request path, captured before Tyk Gateway applies any path-modifying middleware, such as stripping the API's listen path. Equal to `path` unless something changes the path during processing.
</ParamField>

<ParamField path="path">
  URL path of the request.
</ParamField>

<ParamField path="protocol">
  Protocol used in the request (for example, HTTP/1.1).
</ParamField>

<ParamField path="remote_addr">
  Remote address of the client.
</ParamField>

<ParamField path="response_code_details">
  Detailed error description in snake\_case, only present on error requests.
</ParamField>

<ParamField path="response_flag">
  Error classification code, only present on error requests. See [Error Classification](#error-classification).
</ParamField>

<ParamField path="status">
  HTTP response status code.
</ParamField>

<ParamField path="tls_cert_expiry">
  TLS certificate expiration date in RFC 3339 format, only present on TLS certificate errors.
</ParamField>

<ParamField path="tls_cert_subject">
  TLS certificate subject (for example, `CN=api.example.com`), only present on TLS certificate errors.
</ParamField>

<ParamField path="trace_id">
  The OpenTelemetry trace ID for the request (32-character hex W3C trace ID). Only present when OpenTelemetry is enabled and a trace ID is available. Use this to navigate from an access log entry to the corresponding trace in your observability backend.
</ParamField>

<ParamField path="upstream_addr">
  Full upstream address, including scheme, host, and path.
</ParamField>

<ParamField path="upstream_latency">
  Round-trip duration between the gateway sending the request to the upstream service and receiving the response.
</ParamField>

<ParamField path="upstream_status">
  HTTP status code returned by the upstream, only present when the upstream responds with a 5XX status.
</ParamField>

<ParamField path="user_agent">
  User agent string provided by the client.
</ParamField>

## Error Classification

Access logs include a small set of additional fields when a request fails, so you can diagnose problems, such as TLS certificate expiry, connection refusal, or authentication errors, directly from the log without cross-referencing application or API Traffic Logs. Whether a given field appears depends on the specific error; each field's exact conditions are noted in [Access Log Field Reference](#access-log-field-reference) above. Two fields anchor this classification: `response_flag` and `error_source`.

<Note>
  Error classification fields are omitted entirely, not set to an empty string or zero, when they don't apply. This keeps successful requests and errors that don't trigger a given field unchanged.
</Note>

### Response Flags

A response flag is a short, fixed code, such as `UCF` or `AKI`, that classifies the specific error condition Tyk Gateway encountered while processing the request. `response_flag` values are shared with Tyk Gateway's [error response customization](/docs/api-management/custom-error-responses) feature, which uses the same flags to match errors you want to override. See the [Flag Reference](/docs/api-management/custom-error-responses#flag-reference) there for the full list, what each one means, and its typical HTTP status.

### Error Source

`error_source` identifies the Gateway component that generated the error, helping you locate where in the request pipeline the failure occurred. It's present alongside `response_flag` on every error entry.

| error\_source                | Component                                         | Typical flags                            |
| :--------------------------- | :------------------------------------------------ | :--------------------------------------- |
| `ReverseProxy`               | Upstream proxy and transport layer                | `UCF`, `TLE`, `URT`, `DNS`, `CBO`, `NHU` |
| `Upstream`                   | The upstream server itself (responded with error) | `URS`                                    |
| `AuthKey`                    | Auth Token middleware                             | `AMF`, `AKI`, `TKE`                      |
| `Oauth2KeyExists`            | OAuth2 middleware                                 | `AMF`, `AKI`, `EAD`                      |
| `JWTMiddleware`              | JWT middleware                                    | `AMF`, `TKI`, `TCV`, `TKE`               |
| `BasicAuthMiddleware`        | Basic Auth middleware                             | `AMF`, `IHD`, `BIV`                      |
| `RateLimitAndQuotaCheck`     | Rate limiting and quota middleware                | `RLT`, `QEX`                             |
| `APIRateLimitMiddleware`     | API-level rate limiting                           | `RLT`                                    |
| `RequestSizeLimitMiddleware` | Request size limit middleware                     | `BTL`, `CLM`                             |
| `ValidateJSONMiddleware`     | JSON schema validation middleware                 | `BIV`                                    |

### Examples

<AccordionGroup>
  <Accordion title="Upstream connection refused (500)">
    When the upstream server refuses the TCP connection, the access log shows:

    ```
    time="2025-02-10T14:23:01Z" level=info api_id=abc123 api_name=my-api api_type=oas
      error_source=ReverseProxy error_target=api.backend.com:443
      method=GET path=/users prefix=access-log
      response_code_details=connection_refused response_flag=UCF status=500
    ```

    Key fields:

    * `response_flag=UCF` identifies the error as an Upstream Connection Failure.
    * `error_target=api.backend.com:443` shows the specific upstream that refused the connection.
    * `upstream_status` is absent because no HTTP response was received from the upstream.
  </Accordion>

  <Accordion title="TLS certificate expired (500)">
    When the upstream's TLS certificate has expired:

    ```
    time="2025-02-10T14:25:33Z" level=info api_id=abc123 api_name=my-api api_type=oas
      error_source=ReverseProxy error_target=api.backend.com:443
      method=GET path=/users prefix=access-log
      response_code_details=tls_certificate_expired response_flag=TLE status=500
      tls_cert_expiry=2024-01-15T00:00:00Z tls_cert_subject="CN=api.backend.com"
    ```

    The `tls_cert_expiry` and `tls_cert_subject` fields help you identify exactly which certificate needs renewal and when it expired.
  </Accordion>

  <Accordion title="Circuit breaker open (503)">
    When a [circuit breaker](/docs/planning-for-production/ensure-high-availability/circuit-breakers) trips for an endpoint, the access log shows:

    ```
    time="2025-02-10T14:30:00Z" level=info api_id=abc123 api_name=my-api api_type=oas
      circuit_breaker_state=OPEN error_source=ReverseProxy error_target=api.backend.com:443/health
      method=GET path=/health prefix=access-log
      response_code_details=circuit_breaker_open response_flag=CBO status=503
    ```
  </Accordion>

  <Accordion title="Rate limited (429)">
    When a client exceeds the configured rate limit, the access log shows:

    ```
    time="2025-02-10T14:31:22Z" level=info api_id=abc123 api_name=my-api api_type=oas
      error_source=RateLimitAndQuotaCheck method=POST path=/orders prefix=access-log
      response_code_details=session_rate_limited response_flag=RLT status=429
    ```

    Note that `error_target` is absent for gateway-level errors (authentication, rate limiting, validation) because the request did not reach the upstream.
  </Accordion>

  <Accordion title="Upstream returned 503 (5XX passthrough)">
    When the upstream receives the request but responds with an error status, the access log shows:

    ```
    time="2025-02-10T14:32:45Z" level=info api_id=abc123 api_name=my-api api_type=oas
      error_source=Upstream error_target=api.backend.com:443
      method=GET path=/health prefix=access-log
      response_code_details=upstream_response_5xx response_flag=URS status=503
      upstream_status=503
    ```

    Key distinction: `error_source=Upstream` and `upstream_status=503` indicate that the upstream returned an error, unlike a connection failure, where no response was received.
  </Accordion>
</AccordionGroup>

## Performance Considerations

Enabling access logs introduces some performance overhead:

* **Latency:** Increases consistently by approximately 4%-13%, depending on CPU allocation and configuration.
* **Memory Usage:** Memory consumption increases by approximately 6%-7%.
* **Allocations:** The number of memory allocations increases by approximately 5%-6%.

<Note>
  While the overhead of enabling access logs is noticeable, the impact is relatively modest. These findings suggest the performance trade-off may be acceptable depending on the criticality of logging to your application.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Distinguishing Connection Errors from Upstream Response Errors">
    A common troubleshooting question is whether the upstream received the request or if the connection itself failed. The error classification fields make this distinction clear:

    | Scenario                                            | `error_source`  | `upstream_status`          | `error_target` | Example flags              |
    | :-------------------------------------------------- | :-------------- | :------------------------- | :------------- | :------------------------- |
    | Connection failed (upstream never received request) | `ReverseProxy`  | absent (0)                 | present        | `UCF`, `UCT`, `DNS`, `TLE` |
    | Upstream responded with error                       | `Upstream`      | present (for example, 503) | present        | `URS`                      |
    | Gateway rejected request (never proxied)            | middleware name | absent                     | absent         | `RLT`, `AMF`, `BTL`        |
  </Accordion>
</AccordionGroup>
