Overview
Kong AI Gateway (v3.13+) is an API gateway with built-in AI proxy and OpenTelemetry support. Fiddler integrates with Kong at the gateway layer via Kong’sopentelemetry plugin, giving you full LLM observability — prompts, responses, token usage, latency — without adding any SDK to your application code.
Architecture
Kong exposes an OpenAI-compatible endpoint at/openai. Your application requires no SDK — it just calls Kong instead of the provider directly.
Prerequisites
- Fiddler account with a GenAI application already created
- A running Kong Gateway v3.13 or later instance (Gen AI OTel attributes require 3.13)
- A valid LLM provider API key (e.g.
OPENAI_API_KEY) - Your Fiddler API key (found under organizational settings) and application UUID (found under application settings)
Quick Start
Step 1: Create the Kong configuration file
Save the following askong_fiddler_config.yaml. The ${...} values are placeholders — you’ll replace them with your actual values in Step 2. Kong does not read environment variables from its config file, so the real values must be written into the file.
service.name: kong in resource_attributes is required — Fiddler uses this value to recognize and correctly process Kong spans. application.id is also required; spans without it are silently dropped.Step 2: Replace the placeholders with your values
Kong does not read environment variables from its declarative config, so openkong_fiddler_config.yaml and replace each ${...} placeholder with your actual value:
The file now contains secrets — do not commit it. Apply it to your Kong instance the way you already manage Kong configuration — a DB-less declarative file, decK, the Admin API, or your Helm chart’s config.
If you already have a Kong declarative config, you do not need to replace your existing file. Copy just the three plugin entries (
ai-proxy, pre-function, opentelemetry) and add them under your existing plugins: block. The services: and routes: blocks in the example above are only needed if you do not already have an OpenAI route configured.Step 3: Enable tracing on Kong
Theopentelemetry plugin only emits spans if Kong’s tracing is enabled at the process level. These three settings cannot be set in the declarative config — set them wherever your Kong reads its configuration (kong.conf, KONG_* environment variables, or your Helm chart’s env: values):
tracing_instrumentations and tracing_sampling_rate are what make Kong produce OTel spans at all — without them no spans are emitted regardless of the opentelemetry plugin config. untrusted_lua = on is required for the pre-function session-grouping plugin to run its inline Lua.
Step 4: Point your application at Kong
KONG_URL (defaults to http://localhost:8000):
Step 5: Verify traces are arriving
Open the Fiddler UI and navigate to your application’s Explorer. You should see the trace within a few seconds of making your first completion call.Span Type Mapping
Fiddler classifies Kong spans based on the span name andgen_ai.operation.name.
Kong 3.13 names LLM spans "{operation} {model}" (e.g. "chat gpt-4o-mini"). All infrastructure spans start with "kong".
Kong emits a span hierarchy per request: a root HTTP span (
kong), routing and plugin spans (all starting with kong.), and the LLM Gen AI span (named "{operation} {model}"). Only the LLM span is forwarded to Fiddler; Kong’s infrastructure spans are dropped (matching AgentGateway’s LLM-only behaviour). The forwarded LLM span is re-parented to the trace root so it is not flagged as an orphan, and it carries gen_ai.conversation.id, so multi-turn calls sharing one conversation id group under a single Session.
Attribute Mapping
Kong follows the OTel Gen AI semantic conventions. Fiddler’s mapper normalises these automatically:Session Grouping
Each Kong request is its own trace, so without a sharedgen_ai.conversation.id Fiddler falls back to trace_id.hex() and every LLM call shows up as a separate Session. To group a multi-turn conversation into one Session, the same gen_ai.conversation.id must be set on each call’s LLM span.
Kong 3.13 has no native conversation-id field — it only supports W3C traceparent for distributed tracing. The Quick Start config above solves this with the built-in pre-function plugin (this is the approach Kong Support recommends for adding a custom attribute from a request header):
- In the
accessphase it reads theX-Fiddler-Conversation-Idrequest header and stashes it in the per-requestngx.ctx. - In the
header_filterphase it stamps that value asgen_ai.conversation.idon the request’s OTel spans, before theopentelemetryplugin exports them in thelogphase.
header_filter is sufficient: the LLM span already exists at that point, so it always receives the conversation id. There are no later-created infrastructure spans to worry about — they are discarded by Fiddler’s Kong mapper before reaching the UI.
Your application just sends the same header value on every call in a conversation:
Why iterate
ngx.ctx.KONG_SPANS instead of kong.tracing.active_span()? The documented kong.tracing.active_span() returns the root (kong) span, which Fiddler drops as infrastructure. Fiddler keeps only Kong’s Gen AI/LLM span, so the attribute must land on that span — iterating every span guarantees it does, regardless of which span is the LLM one. This approach is verified working on Kong Gateway 3.13 (the version pinned above). ngx.ctx.KONG_SPANS is an internal Kong field rather than a stable public API, so re-verify session grouping after upgrading Kong. The pre-function plugin also requires KONG_UNTRUSTED_LUA=on and a sampling rate of 1.0 (so spans always exist when the plugin runs).traceparent. This is the pattern in Kong’s Voice AI observability cookbook. It avoids the pre-function plugin but requires OTel SDK code in your application.
Troubleshooting
Kong fails to start (missing host in url or similar)
This means the config still contains ${...} placeholders. Kong does not read environment variables — open kong_fiddler_config.yaml and replace every ${...} with your actual value (see Step 2).
Traces not appearing in Fiddler
Verify kong_fiddler_config.yaml has no ${...} placeholders left (every value filled in):
grep -i otel over your Kong proxy/error logs).
Both application.id (OTel resource attribute) and fiddler-application-id (HTTP header on the export request) are required. If either is missing or does not match a valid Fiddler application UUID, spans are silently dropped.
Prompt and response content not showing
log_payloads: true is required in the ai-proxy plugin logging config. Without it, gen_ai.input.messages and gen_ai.output.messages are not captured by Kong, so Fiddler will show token counts and model info but no text content.
Spans not being emitted by Kong
Confirm tracing is enabled at the Kong process level (see Step 3): tracing_instrumentations=all and tracing_sampling_rate=1.0, set as kong.conf settings or KONG_* environment variables. These cannot be configured via the declarative config file.
Span type showing as Unknown
Fiddler routes spans to the Kong mapper when service.name == "kong" on the OTel resource. Verify the resource_attributes block in the opentelemetry plugin config has service.name: kong (exact string match, case-sensitive).
Known Limitations
Related Documentation
- AgentGateway Integration — Fiddler observability via the AgentGateway proxy
- LiteLLM Integration — Fiddler observability via the LiteLLM proxy gateway
- OpenTelemetry Integration — Manual OTel instrumentation for custom frameworks
- OTel Trace Export — Direct OTLP export to Fiddler without a proxy
- Kong AI Gateway documentation — Official Kong AI Gateway docs