Related Documentation
Made by
Kong Inc.
Incompatible with
on-prem
Minimum Version
AI Gateway - 2.0
Tags

The HTTP Log Policy lets you send request and response logs to an HTTP server.

Note: If the max_batch_size argument > 1, a request is logged as an array of JSON objects.

Process errors

This Policy logs request and response data for each proxied request.

The AI Gateway process error file is the Nginx error file. You can find it at the following path:

$PREFIX/logs/error.log

Configure the prefix in kong.conf.

Log format

Every request is logged separately as a JSON object, separated by a new line \n.

When a request is proxied to an LLM service through an AI Model, the log entry also includes an ai.proxy object with the provider, model, token usage, cost, and latency for that request.

Expand this block to see a sample log object for a proxied LLM request
{
    "workspace": "b4a1e9a2-6b4a-4e91-9c2e-3b6a9d8f1c72",
    "workspace_name": "default",
    "source": "upstream",
    "upstream_uri": "/v1/chat/completions",
    "upstream_status": 200,
    "client_ip": "192.168.65.1",
    "started_at": 1787113201719,
    "tries": [
        {
            "ip": "162.159.140.245",
            "port": 443,
            "hostname": "api.openai.com",
            "balancer_latency": 0,
            "balancer_start": 1787113201722,
            "keepalive": true
        }
    ],
    "request": {
        "id": "9ec9264afbbbad5fe5c64877d92eeb04",
        "uri": "/v1/chat/completions",
        "url": "http://localhost:8000/v1/chat/completions",
        "method": "POST",
        "size": 323,
        "querystring": {},
        "headers": {
            "host": "localhost:8000",
            "user-agent": "curl/8.7.1",
            "content-type": "application/json",
            "content-length": "94",
            "authorization": "REDACTED"
        }
    },
    "response": {
        "status": 200,
        "size": 1845,
        "headers": {
            "content-type": "application/json",
            "content-length": "847",
            "date": "Wed, 19 Aug 2026 04:20:02 GMT",
            "server": "cloudflare",
            "via": "1.1 kong/2.0.2-ai-gateway",
            "x-kong-request-id": "9ec9264afbbbad5fe5c64877d92eeb04",
            "x-kong-proxy-latency": "3",
            "x-kong-upstream-latency": "970",
            "x-kong-llm-model": "openai/gpt-4o",
            "x-ratelimit-remaining-requests": "4999",
            "x-ratelimit-remaining-tokens": "799993",
            "openai-organization": "org-example123456",
            "openai-project": "proj_example7890abcd"
        }
    },
    "latencies": {
        "kong": 3,
        "proxy": 970,
        "request": 976,
        "receive": 3
    },
    "service": {
        "id": "947a4e23-b483-5a65-8165-da9aed24565b",
        "name": "ai-gateway",
        "host": "ai-gateway.upstream.local",
        "port": 80,
        "protocol": "http"
    },
    "route": {
        "id": "8ae36805-da7a-55b9-b056-72bde6bb937d",
        "name": "openai-chat",
        "paths": ["/v1/chat/completions"],
        "methods": ["POST"]
    },
    "ai": {
        "proxy": {
            "tried_targets": [
                {
                    "route_type": "llm/v1/chat",
                    "provider": "openai",
                    "host": "api.openai.com",
                    "port": 443,
                    "upstream_scheme": "https",
                    "upstream_uri": "/v1/chat/completions",
                    "model": "gpt-4o"
                }
            ],
            "meta": {
                "request_mode": "oneshot",
                "provider_name": "openai",
                "request_model": "gpt-4o",
                "response_model": "gpt-4o-2024-08-06",
                "operation_name": "chat",
                "llm_latency": 972,
                "plugin_id": "f3adc007-171c-5519-8763-3a0eef79bde3"
            },
            "usage": {
                "prompt_tokens": 13,
                "completion_tokens": 12,
                "total_tokens": 25,
                "cost": 0,
                "time_per_token": 81,
                "time_to_first_token": 971
            }
        }
    }
}

The following table describes the core objects in the log. For a full breakdown of the ai.* fields shown in the previous example, see AI Gateway logs.

Log item

Description

service Properties of the AI Gateway Service associated with the requested Route.
route Properties of the specific Route requested.
request Properties of the request sent by the client.
response Properties of the response sent to the client.
latencies Latency data for the request.
tries A list of iterations made by the load balancer for this request, including each upstream target that was tried.
client_ip The original client IP address.
upstream_uri The URI, including query parameters, for the configured upstream service.
consumer The authenticated AI Consumer. Only present if authentication is enabled.
started_at The Unix timestamp of when the request started to be processed.
source Indicates whether the response is generated by kong or upstream.
upstream_status The status code received from the upstream service in the response.
ai Present only for requests proxied to an LLM. Contains provider, model, usage, cost, and cache metrics, keyed by Policy name (for example, ai.proxy).

Queuing

The HTTP Log Policy uses internal queues to decouple the production of log entries from their transmission to the upstream server.

With queuing, entries are placed in a configurable queue before being sent in batches to the upstream server. This has the following benefits:

  • Reduces concurrency on the upstream server
  • Helps deal with temporary outages of the upstream server due to network or administrative changes
  • Can reduce resource usage both in AI Gateway and on the upstream server by collecting multiple entries from the queue in one request

Note: Because queues are structural elements for components in AI Gateway, they only live in the main memory of each worker process and aren’t shared between workers. Therefore, queued content isn’t preserved under abnormal operational situations, like power loss or unexpected worker process shutdown due to memory shortage or program errors.

You can configure several parameters for queuing:

Parameters

Description

Queue capacity limits:

config.queue.max_entries
config.queue.max_bytes
config.queue.max_batch_size
Configure sizes for various aspects of the queue: maximum number of entries, batch size, and queue size in bytes.

When a queue reaches the maximum number of entries and another entry is enqueued, the oldest entry in the queue is deleted to make space for the new entry. The queue code logs a warning when it reaches a capacity threshold of 80% and when it starts to delete entries from the queue, and logs again when the situation normalizes.
Timer usage:

config.queue.concurrency_limit
Only one timer is used to start queue processing in the background by default. Once the queue is empty, the timer handler terminates, and a new timer is created as soon as a new entry is pushed onto the queue.
Retry logic:

config.queue.initial_retry_delay
config.queue.max_coalescing_delay
config.queue.max_retry_delay
config.queue.max_retry_time
If a queue fails to process, it can automatically retry if the failure is temporary, for example due to network problems or upstream unavailability.

Shared queues in HTTP Log Policy instances

In contrast to other Policies that use queues, all HTTP Log Policy instances that have the same values for the following parameters share one queue:

Custom fields by Lua

The config.custom_fields_by_lua configuration lets you dynamically modify log fields using Lua code. The following example configuration removes the route field from the logs:

New fields can be added the same way:

Dot characters (.) in the field key create nested fields. Use a backslash \ to escape a dot if you want to keep it as part of a flat field name instead of nesting it. For example, [my_entry.log\.field] produces a my_entry object with a single log.field key, instead of nesting into log and field.

Targeting AI Gateway fields

AI Gateway logs the outcome of an LLM request under a nested ai object, for example ai.$POLICY_NAME.meta, ai.$POLICY_NAME.usage, and, when payload logging is enabled, ai.$POLICY_NAME.payload.request and ai.$POLICY_NAME.payload.response. Because custom_fields_by_lua keys are split into nested table accesses the same way, you can use the same unescaped, dotted-key syntax to remove or override those fields.

For example, to stop logging LLM request and response payloads:

Note: Escaping the dots (for example, ai\.http-log\.payload\.request) targets a literal flat key instead of the nested ai.http-log.payload.request field, so it won’t match. Use unescaped dots to target AI Gateway fields.

Because HTTP Log applies custom_fields_by_lua in its own log phase, which runs after AI Gateway sets the ai.* fields on the request, it can override or remove any ai.* field. The reverse isn’t possible, since AI Gateway can’t run after a logging Policy’s log phase to override a field the Policy already set.

Policy precedence and managing fields

All logging Policies use the same table for logging. If you set config.custom_fields_by_lua in one Policy, all logging Policies that run after it also use that configuration. For example, if you configure fields in the File Log Policy, those same fields appear in the Syslog Policy too, since File Log executes first.

  • If you want all logging Policies to use the same configuration, use the Pre-function Policy to call kong.log.set_serialize_value so the function is applied predictably and is easier to manage.
  • If you don’t want all logging Policies to share the same configuration, disable the relevant field in each Policy explicitly. For example, if you configure a field in the File Log Policy that you don’t want appearing in the Syslog Policy, set that field to return nil in the File Log Policy’s custom_fields_by_lua configuration.

Limitations

Lua code runs in a restricted sandbox environment, whose behavior is governed by the untrusted_lua configuration.

As this code runs in the log phase, only PDK methods that can run in that phase can be used.

FAQs

The log is executed after AI Gateway sends the last response byte to the client.

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!