Overview
Kong AI Gateway (3.13 or later) 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.
Kong’s Gen AI OpenTelemetry tracing is labelled Tech Preview by Kong — “currently in Tech Preview and should not be used in a production environment.” This page’s tracing setup is built on that feature; re-verify after Kong upgrades. The current Kong Gateway release is 3.15.0.3 (as of 2026-08-19); the 3.13+ floor is the minimum that emits Gen AI span attributes.
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 3.13+ 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. Kong performs no shell-style ${VAR} substitution in its declarative config, so the ${...} placeholders below must be handled one of two ways. On fields Kong marks referenceable — such as ai-proxy’s auth.header_value — you can use a Kong Vault reference like {vault://env/OPENAI_KEY}, which Kong resolves from an environment variable at runtime (supported in declarative config on OSS and Enterprise alike, at no license cost). On non-referenceable fields you replace the placeholder with the real value in Step 2. The example uses a vault reference for the provider key and literal replacement for the rest.
service.name: kong in resource_attributes is how Fiddler routes Kong spans to its Kong mapper, and setting it is the documented default on every release. From 26.17, Fiddler also recognizes Kong’s kong-internal instrumentation scope; scope-based routing is evaluated first, so a Kong span is routed correctly even if a deployment overrides service.name. application.id is also required: a resource with no application.id is skipped — Fiddler logs a warning and increments a missing_application_id_failure counter, so the drop is visible in ingestion logs and metrics rather than silent.Step 2: Replace the Placeholders With Your Values
Supply each value the way its field allows. Kong resolves a{vault://env/...} reference only on referenceable fields; on all other fields you replace the ${...} placeholder with the literal value before starting Kong.
Because the Fiddler API key must be written in literally, the finished file contains a live secret: restrict its file permissions and inject it at deploy time from your secret manager rather than committing it. If any
${...} placeholder is left unreplaced, Kong fails to start with an error like 'traces_endpoint': missing host in url. Apply the config the way you already manage Kong — 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-5-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}"). Fiddler keeps only the spans it classifies — the LLM span, plus a fiddler-guardrail span if you run guardrails — and drops every other Kong-resource span. That includes infrastructure spans and any Gen AI operation outside chat, text_completion, and generate_content: an embeddings call through the same route is dropped with no separate signal. Kong is the only Fiddler integration that filters its own infrastructure spans this way. The forwarded LLM span 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 normalizes 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. ngx.ctx.KONG_SPANS is an internal Kong field rather than a stable public API. This mechanism has no automated test coverage in Fiddler — no unit, fixture, or e2e case exercises the header-to-ngx.ctx-to-attribute path or the KONG_UNTRUSTED_LUA requirement — and Kong has no local Fiddler harness, so treat it as manually verified only and re-verify session grouping after every Kong upgrade. 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). If you would rather not depend on an internal field, use the application-side alternative below.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.
Guardrails
Beyond tracing, Kong can enforce Fiddler Guardrails on prompts before they reach the model — blocking PII and secrets at the gateway via Kong’sai-custom-guardrail plugin (which requires Kong 3.14+ with an AI Gateway Enterprise license). The guardrail plugin’s own check function can also emit a connected Guardrail span in the same trace as the LLM span.
See Kong Guardrails for setup, check behavior, and the full configuration.
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 application.id is missing, Fiddler skips those spans, logs a warning, and increments a missing_application_id_failure counter — so check your Fiddler ingestion logs and metrics if traces are absent. Fiddler checks that the attribute is present; it does not validate the UUID’s format at this stage.
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, or unexpected extra spans in the trace
Fiddler routes Kong spans to its Kong mapper by service.name == "kong" (exact string match, case-sensitive) and, from 26.17, also by the kong-internal instrumentation scope. Verify the resource_attributes block in the opentelemetry plugin config has service.name: kong. The same routing decision also gates the dropping of Kong’s infrastructure spans, so a mismatch has two symptoms at once: LLM spans show as Unknown, and Kong’s infrastructure spans stop being filtered out, appearing as extra orphaned spans in the trace.
For guardrail-specific troubleshooting, see Kong Guardrails → Troubleshooting.
Known Limitations
Deployment Modes
Fiddler’s Kong tracing works wherever Kong runs theopentelemetry plugin and can export over HTTPS. Two conveniences documented here and on the guardrails page — the pre-function session-grouping plugin and the guardrail check function — additionally require untrusted_lua = on, a process-level setting that some managed Kong offerings do not expose.
Unverified means Fiddler has not confirmed the mode — it is not a statement that the mode is unsupported. If your managed gateway does not allow untrusted_lua = on, use the application-side session-grouping alternative, which needs no Kong plugin.
Next Steps
- Kong Guardrails — block PII and secrets at the Kong gateway.
- AgentGateway Integration — add Fiddler observability through the AgentGateway proxy.
- LiteLLM Integration — add Fiddler observability through the LiteLLM proxy.
- OpenTelemetry Integration — instrument a custom framework with the OTel SDK.
- OTel Trace Export — export OTLP directly to Fiddler without a proxy.
- Kong AI Gateway documentation — Kong’s official AI Gateway docs.