> ## 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.

# Application and Access Logs

> Learn about the different types of logs in Tyk, how to configure them and how to integrate with third-party log management tools for effective API observability.

A log is a timestamped text record, either structured (recommended) or unstructured, with some metadata.

<Note>
  Tyk logs are written to `stderr`. In a typical installation, these will be handled by the service manager running the process.
</Note>

## Types of Logs

Tyk generates four types of logs:

* **[Application Log](#application-logs):** Internal system events such as health-checks, configuration changes, and errors. Written to `stderr` and consumed by your log aggregator or service manager.
* **[API Traffic Log](/api-management/tyk-pump#api-traffic-logs):** <Badge color="orange">Gateway</Badge> A record of every API request, written into Redis and processed by Tyk Pump for analytics and reporting. Not written to `stderr`.
* **[Access Log](#access-logs):** <Badge color="orange">Gateway</Badge> Per-request server logs written to `stderr`, intended for external log aggregators. Similar to API Traffic Logs in that both record individual requests, but Access Logs are lightweight and real-time whereas API Traffic Logs are richer and processed asynchronously.
* **[Audit Log](/api-management/dashboard-configuration#dashboard-audit-logs):** <Badge color="blue">Dashboard</Badge> A record of user actions in Tyk Dashboard, such as API changes and login events.

This page covers the configuration and behavior of Application Logs and Access Logs. API Traffic Logs and Dashboard Audit Logs are documented separately.

## Configuring Logs

Application logs and Tyk Gateway access logs are written to `stderr`. Three aspects can be configured: **verbosity** (which severity levels are written), **format** (the structure and timestamp style of each entry), and **log output** (where logs are sent, for example to a third-party aggregator).

Both verbosity and format can be controlled globally across all components, or per component for finer control. Global settings take priority over component-specific ones.

### Global Settings

Two environment variables apply across multiple components and override any component-specific setting:

| Setting   | Environment variable | Applies to                                 |
| :-------- | :------------------- | :----------------------------------------- |
| Verbosity | `TYK_LOGLEVEL`       | All components except Tyk Developer Portal |
| Format    | `TYK_LOGFORMAT`      | Tyk Gateway, Tyk Dashboard, Tyk Pump       |

### Component Settings

When global variables are not set, each component can be configured individually using environment variables or the equivalent `log_level` and `log_format` settings in its configuration file.

All components default to `info` verbosity and `text` format. Tyk Developer Portal is an exception: it defaults to `prod` format, which is equivalent to `json`.

| Tyk component                                                                                                | Log level env var                  | Log format env var  | Supported formats        |
| :----------------------------------------------------------------------------------------------------------- | :--------------------------------- | :------------------ | :----------------------- |
| [Tyk Gateway](/tyk-oss-gateway/configuration#log_level)                                                      | `TYK_GW_LOGLEVEL`                  | `TYK_GW_LOGFORMAT`  | `text`, `json`, `legacy` |
| [Tyk Pump](/tyk-pump/tyk-pump-configuration/tyk-pump-environment-variables#log_level)                        | `TYK_PMP_LOGLEVEL`                 | `TYK_PMP_LOGFORMAT` | `text`, `json`, `legacy` |
| [Tyk Dashboard](/tyk-dashboard/configuration#log_level)                                                      | `TYK_DB_LOGLEVEL` (from `v5.14.0`) | `TYK_DB_LOGFORMAT`  | `text`, `json`           |
| [Tyk MDCB](/tyk-multi-data-centre/mdcb-configuration-options#log_level)                                      | `TYK_MDCB_LOGLEVEL`                | N/A                 | Legacy text only         |
| [Tyk Developer Portal](/product-stack/tyk-enterprise-developer-portal/deploy/configuration#portal_log_level) | `PORTAL_LOG_LEVEL`                 | `PORTAL_LOG_FORMAT` | `text`, `json`           |

<Note>
  The `legacy` format was introduced in Tyk Gateway 5.14.0 and Tyk Pump 5.14.0 to maintain backward compatibility for existing users with log pipelines reliant on the precise log content. See [legacy format](/api-management/logs#legacy-format).
</Note>

### Severity and Verbosity

The severity of a log is an indication of its likely importance to the system administrator. The system will generate logs at four different levels of severity:

| Severity    | Purpose                                                                                                                        | Example                                          |
| :---------- | :----------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------- |
| Error       | Conditions that require immediate attention, such as a component being unreachable or a request failing due to a system fault. | Failed to connect to Redis                       |
| Warning     | Potential issues or degraded behavior that may require investigation, but do not prevent the system from operating.            | Configuration value out of bounds, using default |
| Information | Normal operational events confirming the system is functioning as expected. This is the default level.                         | Gateway started, API loaded, access log entries  |
| Debug       | Detailed diagnostic output useful for troubleshooting, such as middleware execution steps and request routing decisions.       | Middleware execution details                     |

Each component can individually be configured to output only the logs generated at or above a given severity level by setting the **log level** as follows:

* `error`: only errors are logged
* `warn`: warnings and errors are logged
* `info`: errors, warnings, and informational messages are logged (default)
* `debug`: all of the above, plus detailed diagnostic output

All access logs are written at `info` level. Setting verbosity to `warn` or `error` will suppress generation of access log output.

<Warning>
  Debug log level generates a significant amount of data and is not recommended unless debugging.
</Warning>

### Format Options

Log format controls the structure and timestamp style of all log output from a component. The supported values are `text` (default), `json` (recommended), and `legacy`.

<Tip>
  As a general performance tip, the `json` output format incurs less memory allocation overhead than the `text` format. For optimal performance, it's recommended to configure logging in the JSON format.
</Tip>

<Tabs>
  <Tab title="Text Format">
    ```
    time="2024-09-05T09:04:12Z" level=info message="Tyk API Gateway v5.14.0" prefix=main
    ```
  </Tab>

  <Tab title="JSON Format">
    ```json theme={null}
    {"level":"info","message":"Tyk API Gateway v5.14.0","prefix":"main","time":"2024-09-05T09:04:12Z"}
    ```
  </Tab>

  <Tab title="Legacy Format">
    Preserves the previous timestamp format and `msg` field key:

    ```
    time="Sep 05 09:04:12" level=info msg="Tyk API Gateway v5.14.0" prefix=main
    ```
  </Tab>
</Tabs>

#### Legacy Format

From Tyk Gateway 5.14.0 and Tyk Pump 5.14.0, the `text` and `json` formats use RFC3339 timestamps and a standardized `message` field.

If your log pipeline relies on the previous timestamp format (`Dec 12 13:50:45`) or the `msg` field key, set `log_format` to `legacy` to preserve the old behavior.

### Log Output

By default, Tyk components write their log output to `stderr`.

Tyk can also forward logs to a third-party aggregator, in addition to `stderr` output, which continues regardless. Tyk Gateway supports Sentry, Logstash, Graylog, and syslog; Tyk Dashboard supports Sentry only. Add the relevant settings to `tyk.conf` for Tyk Gateway, or `tyk_analytics.conf` for Tyk Dashboard (or use the equivalent environment variables):

<Tabs>
  <Tab title="Sentry">
    <Badge color="orange">Gateway</Badge> <Badge color="blue">Dashboard</Badge>

    * `use_sentry`: Set to `true` to enable output to [Sentry](https://sentry.io/product/logs/).
    * `sentry_code`: The Sentry-assigned DSN (endpoint URL) to which the logs are sent.
  </Tab>

  <Tab title="Logstash">
    <Badge color="orange">Gateway Only</Badge>

    * `use_logstash`: Set to `true` to enable output to [Logstash](https://www.elastic.co/logstash).
    * `logstash_transport`: Set this to `"tcp"`.
    * `logstash_network_addr`: The network address of the Logstash server, in the form `hostname:port`.
  </Tab>

  <Tab title="Graylog">
    <Badge color="orange">Gateway Only</Badge>

    * `use_graylog`: Set to `true` to enable output to [Graylog](https://graylog.org/).
    * `graylog_network_addr`: The network address of the Graylog server, in the form `hostname:port`.
  </Tab>

  <Tab title="Syslog">
    <Badge color="orange">Gateway Only</Badge>

    * `use_syslog`: Set to `true` to enable output to syslog.
    * `syslog_transport`: Set to `"udp"` to send to a remote syslog server, or leave empty to use the local Unix socket.
    * `syslog_network_addr`: The network address of the syslog server, in the form `hostname:port`.
  </Tab>
</Tabs>

## Application Logs

Application logs capture internal events of the system, such as health-checks, status, configuration changes, and errors, which are typically used for monitoring and debugging.

**Example**

```
time="2025-02-16T22:48:39Z" level=info message="Using Policies from Dashboard Service" prefix=main
time="2025-02-16T22:48:39Z" level=info message="Calling dashboard service for policy list" prefix=policy
time="2025-02-16T22:48:39Z" level=info message="Processing policy list" prefix=policy
time="2025-02-16T22:48:39Z" level=info message="Policies found (5 total):" prefix=main
```

### OpenTelemetry Trace and Span IDs

<Badge color="orange">Gateway Only</Badge>

When OpenTelemetry tracing is enabled, Tyk Gateway automatically injects `trace_id` and `span_id` fields into all request-scoped application log entries, including middleware execution, error handling, and debug output. This lets you correlate an application log line with the corresponding span in your distributed trace.

```
time="2025-02-16T22:48:39Z" level=error message="Rate limit exceeded" prefix=rate-limit api_id=b1a41c9a89984ffd7bb7d4e3c6844ded trace_id=4bf92f3577b34da6a3ce929d0e0e4736 span_id=00f067aa0ba902b7
```

Non-request-scoped entries (startup, configuration reload, health-checks) do not carry trace or span IDs because they are not associated with a specific request.

### Tracking HTTP 404 Errors

<Badge color="orange">Gateway Only</Badge>

By default, requests that do not match any configured API listen path return HTTP 404 and are not logged. Because these requests never enter the proxy pipeline, they are not recorded in Access Logs or API Traffic Logs, which only cover requests that are routed and processed by the Gateway.

To track them in the application log, set [`track_404_logs`](/tyk-oss-gateway/configuration#track_404_logs) to `true` in `tyk.conf` (or the equivalent environment variable).

When enabled, a log entry is written at `error` level for each unmatched request.

From **Tyk Gateway 5.14.0**, the entry includes a `host` field when using the `text` or `json` log format. Because Tyk Gateway exposes both a proxy API and a control API, and these can be [configured on a separate hostname and port](/planning-for-production#change-your-control-port), the `host` field identifies which one received the unmatched request:

```
time="2025-07-15T10:25:30Z" level=error message="Not Found" prefix=gateway request="GET /nonexistent/path HTTP/1.1" origin=192.168.1.5:54321 host=api.example.com:9696
```

In `legacy` format, the `host` field is omitted:

```
time="Jul 15 10:25:30" level=error msg="Not Found" prefix=gateway request="GET /nonexistent/path HTTP/1.1" origin=192.168.1.5:54321
```

### Event Log Handlers

<Badge color="orange">Gateway Only</Badge>

[Event log handlers](/api-management/gateway-events#logging-api-events) can be registered against Gateway events to write a log entry each time a specific event fires, such as an authentication failure or rate limit being exceeded.

## Access Logs

<Badge color="orange">Gateway Only</Badge> <Badge color="orange">Not available in Tyk Cloud</Badge>

Access logs are simple, traditional server logs that record basic information about each request to your API Gateway and are written directly to stdout/stderr.

As of Tyk Gateway v5.8.0, you can configure the Gateway to log individual API requests. To enable this feature, set the `TYK_GW_ACCESSLOGS_ENABLED` environment variable to `true`.

You can also configure which fields are logged by configuring the `TYK_GW_ANALYTICSLOGS_TEMPLATE` environment variable. Below are the available values you can include:

### Configurable Fields

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

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

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

<ParamField path="method">
  HTTP method used in the request (for example, GET or POST).
</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="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="latency_total">
  Total time taken to process the request, including upstream latency and additional gateway processing.
</ParamField>

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

<ParamField path="status">
  HTTP response status code.
</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="response_flag">
  Error classification code, only present on error requests. See Error Classification Fields.
</ParamField>

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

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

<ParamField path="error_target">
  Upstream address for proxy errors, only present on error requests.
</ParamField>

<ParamField path="upstream_status">
  HTTP status from upstream for passthrough errors, only present when upstream responded.
</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="circuit_breaker_state">
  Circuit breaker state (for example, `OPEN`), only present on circuit breaker errors.
</ParamField>

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

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

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

<ParamField path="mcp_primitive_name">
  Name of the MCP tool, resource, or prompt that was invoked. Only present on MCP API requests.
</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>

#### Default Template Example

<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>

Output:

```
time="Jan 29 08:27:09" level=info api_id=b1a41c9a89984ffd7bb7d4e3c6844ded api_key=00000000 api_name=httpbin api_type=oas client_ip="::1" host="localhost:8080" latency_total=62 method=GET org_id=678e6771247d80fd2c435bf3 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
```

#### Custom Template 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="Jan 29 08:27:48" level=info api_id=b1a41c9a89984ffd7bb7d4e3c6844ded api_key=00000000 api_name=httpbin api_type=oas org_id=678e6771247d80fd2c435bf3 prefix=access-log remote_addr="[::1]:63270" upstream_addr="http://httpbin.org/get"
```

### Error Classification

Access logs automatically include structured error classification fields for failed requests. These fields help developers quickly identify root causes, such as TLS certificate expiry, connection refusal, rate limiting, or authentication errors, directly from the access log without cross-referencing application or API Traffic Logs.

<Note>
  Error classification fields appear only when errors occur; successful requests do not include them.
</Note>

#### Log Field Reference

| Field                   | Type    | Description                                      | Present when                |
| :---------------------- | :------ | :----------------------------------------------- | :-------------------------- |
| `response_flag`         | String  | 3-letter code identifying the error category     | Always (on error)           |
| `response_code_details` | String  | snake\_case description of the specific error    | Always (on error)           |
| `error_source`          | String  | Gateway component where the error originated     | Always (on error)           |
| `error_target`          | String  | Upstream address being accessed                  | Upstream/proxy errors       |
| `upstream_status`       | Integer | HTTP status code returned by the upstream        | Upstream responded with 5XX |
| `tls_cert_expiry`       | String  | Certificate expiration date (RFC 3339)           | TLS certificate errors      |
| `tls_cert_subject`      | String  | Certificate subject (e.g., `CN=api.example.com`) | TLS certificate errors      |
| `circuit_breaker_state` | String  | State of the circuit breaker (e.g., `OPEN`)      | Circuit breaker errors      |

<Note>
  Fields with empty or zero values are omitted from the log entry rather than being set to empty strings or zero. This keeps successful request logs unchanged and error logs concise.
</Note>

#### Response Flags: Upstream and Proxy Errors (5XX)

These flags indicate errors occurring when the gateway proxies requests to the upstream service.

| Flag  | Name                    | HTTP Status | Description                                                                                       |
| :---- | :---------------------- | :---------- | :------------------------------------------------------------------------------------------------ |
| `TLE` | TLS Certificate Expired | 502         | The upstream server's TLS certificate has expired                                                 |
| `TLI` | TLS Certificate Invalid | 502         | The upstream's TLS certificate failed validation                                                  |
| `TLM` | TLS Hostname Mismatch   | 502         | The certificate's CN/SAN does not match the hostname                                              |
| `TLN` | TLS Not Trusted         | 502         | The certificate was issued by an unknown authority                                                |
| `TLH` | TLS Handshake Failure   | 502         | The TLS handshake failed (bad certificate, client cert required)                                  |
| `TLP` | TLS Protocol Error      | 502         | TLS protocol or version mismatch                                                                  |
| `TLA` | TLS Alert               | 502         | A TLS alert was received from the upstream                                                        |
| `UCF` | Connection Refused      | 502         | The upstream server refused the TCP connection                                                    |
| `UCT` | Connection Timeout      | 502         | The TCP connection to the upstream timed out                                                      |
| `URR` | Connection Reset        | 502         | The connection was reset by the upstream server                                                   |
| `EPI` | Broken Pipe             | 502         | The connection was closed unexpectedly (EPIPE)                                                    |
| `URT` | Response Timeout        | 504         | The upstream did not respond within the timeout period                                            |
| `DNS` | DNS Resolution Failure  | 502         | The upstream hostname could not be resolved                                                       |
| `NRH` | No Route to Host        | 502         | The upstream host or network is unreachable                                                       |
| `NHU` | No Healthy Upstreams    | 503         | All upstream targets in the load balancer are unhealthy                                           |
| `CBO` | Circuit Breaker Open    | 503         | The [circuit breaker](/planning-for-production/ensure-high-availability/circuit-breakers) is open |
| `URS` | Upstream Response 5XX   | 5XX         | The upstream returned a 5XX status code                                                           |
| `UPE` | Upstream Error          | 5XX         | A generic upstream error that did not match a specific pattern                                    |

#### Response Flags: Gateway Errors (4XX)

These flags indicate errors within the gateway's middleware pipeline before the request reaches the upstream. The `error_source` field identifies the middleware that rejected the request.

<Tabs>
  <Tab title="Authentication Errors">
    | Flag  | Name                 | HTTP Status | Description                                                          |
    | :---- | :------------------- | :---------- | :------------------------------------------------------------------- |
    | `AMF` | Auth Field Missing   | 400 or 401  | The authorization header or parameter is missing                     |
    | `AKI` | API Key Invalid      | 403         | The API key was not found or is invalid                              |
    | `TKE` | Token Expired        | 403         | The JWT, OAuth token, or client certificate has expired              |
    | `TKI` | Token Invalid        | 403         | The JWT or OAuth token is malformed or has an invalid signature      |
    | `TCV` | Token Claims Invalid | 401         | JWT claims validation failed (e.g., issuer, audience, custom claims) |
    | `EAD` | External Auth Denied | 403         | An external authentication service denied the request                |

    <Note>
      The HTTP status code for `AMF` varies by middleware: Auth Token middleware returns `401`, while OAuth2 and JWT middleware return `400`. The `response_flag` is the same, but `error_source` identifies the middleware that generated the error.
    </Note>
  </Tab>

  <Tab title="Rate Limiting Errors">
    | Flag  | Name           | HTTP Status | Description                                  |
    | :---- | :------------- | :---------- | :------------------------------------------- |
    | `RLT` | Rate Limited   | 429         | The request was rejected due to a rate limit |
    | `QEX` | Quota Exceeded | 403         | The client's usage quota has been exhausted  |
  </Tab>

  <Tab title="Request Validation Errors">
    | Flag  | Name                   | HTTP Status | Description                                                   |
    | :---- | :--------------------- | :---------- | :------------------------------------------------------------ |
    | `BTL` | Body Too Large         | 400         | The request body exceeds the configured size limit            |
    | `CLM` | Content-Length Missing | 411         | The Content-Length header is required but was not provided    |
    | `BIV` | Body Invalid           | 400 or 422  | The request body is malformed or fails JSON schema validation |
    | `IHD` | Invalid Header         | 400         | A required request header is malformed or invalid             |
  </Tab>

  <Tab title="Client Connection Errors">
    | Flag  | Name                | HTTP Status | Description                                                 |
    | :---- | :------------------ | :---------- | :---------------------------------------------------------- |
    | `CDC` | Client Disconnected | 499         | The client closed the connection before a response was sent |
  </Tab>
</Tabs>

#### Understanding error\_source

The `error_source` field identifies the gateway component that generated the error, helping you locate where the failure occurred in the request processing pipeline.

| 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 (502)">
    When the upstream server refuses the TCP connection, the access log shows:

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

    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 (502)">
    When the upstream's TLS certificate has expired:

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

    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](/planning-for-production/ensure-high-availability/circuit-breakers) trips for an endpoint, the access log shows:

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

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

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

    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="Feb 10 14:32:45" level=info api_id=abc123 api_name=my-api api_type=oas
      status=503 response_flag=URS response_code_details=upstream_response_5xx
      error_source=Upstream error_target=api.backend.com:443
      upstream_status=503
      method=GET path=/health prefix=access-log
    ```

    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>

### MCP Access Log Fields

When a request is proxied through an MCP API, Tyk adds MCP-specific fields to the access log entry. These fields are omitted when empty, so non-MCP request logs are unchanged.

#### Log Field Reference

| Field                | Type   | Description                                                                | Present when        |
| :------------------- | :----- | :------------------------------------------------------------------------- | :------------------ |
| `api_type`           | String | API type: `mcp`, `graphql`, `oas`, or `classic`                            | Always              |
| `mcp_method`         | String | JSON-RPC method called (e.g. `tools/call`, `initialize`, `resources/read`) | MCP requests        |
| `mcp_primitive_type` | String | MCP primitive type: `tool`, `resource`, or `prompt`                        | MCP requests        |
| `mcp_primitive_name` | String | Name of the tool, resource, or prompt invoked                              | MCP requests        |
| `mcp_error_code`     | String | JSON-RPC error code (e.g. `-32001`, `-32002`)                              | MCP error responses |

<Note>
  MCP fields are omitted when empty, consistent with the existing access log behavior for error fields. Non-MCP request logs are unaffected.
</Note>

#### Examples

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

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

    Key fields:

    * `api_type=mcp` identifies this as an MCP API 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="Apr 07 10:16:02" level=info api_id=mcp-weather-api api_name=weather-mcp api_type=mcp
      method=POST path=/mcp status=200 latency_total=38
      mcp_method=tools/call mcp_primitive_type=tool mcp_primitive_name=get_forecast
      mcp_error_code=-32602
      prefix=access-log
    ```

    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>

### 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 (e.g., 503) | present        | `URS`                      |
    | Gateway rejected request (never proxied)            | middleware name | absent              | absent         | `RLT`, `AMF`, `BTL`        |
  </Accordion>
</AccordionGroup>
