opentelemetry plugin exports four streams over OTLP/HTTP: request traces, access logs, the gateway’s runtime log, and metrics. Point all four at Bronto and the gateway becomes the only thing emitting telemetry — no Collector, no sidecar, no application instrumentation. It works the same for a self-managed gateway and a Konnect-managed data plane.
Prerequisites
- A Bronto account and API key (how to create one)
- Kong Gateway 3.13 or later for access logs and metrics (verified with 3.16). On 3.13, use the flat
access_logs_endpointfield in place ofaccess_logs.endpoint - A way to apply plugin configuration — the examples use decK, but the Admin API and Konnect UI take the same fields
Enable tracing and runtime logs on the data plane
Set these in the data plane’s environment and restart it:KONG_TRACING_INSTRUMENTATIONS is off by default, and without it the plugin has no spans to export. KONG_LOG_LEVEL=info is optional: at the default notice the runtime log channel is almost silent. Lower KONG_TRACING_SAMPLING_RATE for high-traffic gateways.
Configure the OpenTelemetry plugin
Add the plugin globally so it covers every route:kong.yaml
<REGION> to eu or us, export DECK_BRONTO_API_KEY, then apply it:
- Each signal takes its full URL. Kong does not append
/v1/...to a base host. Runtime logs (logs_endpoint) and access logs (access_logs.endpoint) are separate streams, so both need setting. - Use the nested
access_logs.endpoint. The flataccess_logs_endpointfield is deprecated from 3.14. - An endpoint alone exports no metrics. Every
enable_*flag defaults tofalse. Two more exist:enable_ai_metricsadds AI Gateway metrics, andenable_principal_attribute(3.16+) tags metrics with the authenticated principal.push_intervaldefaults to60seconds. service.nameandservice.namespaceselect the log dataset and collection. Traces and metrics don’t belong to a dataset; they appear in Explore Traces and Metric Explorer under the sameservice.name.http_response_header_for_traceidreturns the trace ID to the client on every response, so a caller can find its own request in Bronto.${{ env "DECK_..." }}is resolved by decK at sync time, which keeps the key out ofkong.yaml. decK only exposes variables with theDECK_prefix. The resolved key is still stored in the gateway’s configuration; to keep it out of that too, use a vault reference as the header value.
Configure in the Konnect UI
The same settings are available in Konnect without decK. Open API Gateway → Control planes, select your control plane, then Plugins → New plugin and choose OpenTelemetry.- Plugin scope: choose Global to cover every service and route.
- Plugin configuration: fill in Traces endpoint, Logs endpoint, Access logs → Endpoint and Metrics → Endpoint with the four URLs above, then switch on the Enable … metrics toggles under Metrics.
- Select Show additional settings under Plugin configuration. This reveals the fields the main form hides:
- Headers: key
x-bronto-api-key, with your API key — or a vault reference — as the value - Resource attributes:
service.nameandservice.namespace - HTTP response header for TraceID:
X-Trace-Id - Sampling rate:
1
- Headers: key
- Select View configuration to check the result against the YAML above, then Save.
Store the API key in a vault
Every header value and endpoint field has a Look up key in vault link. It lists the vaults configured on the control plane, so create one first under Vaults → New vault:- Konnect keeps the secret in Konnect itself, with nothing to set up on the data plane.
- Environment variables reads it from the data plane’s environment, alongside the
KONG_*variables above.
{vault://<vault-prefix>/<secret-id>}, resolved by the data plane at runtime. A reference must be the whole field value. Store the bare API key as the secret, not x-bronto-api-key: plus the key — the header name stays in the Headers key field.
With decK, the equivalent is a vaults entry and a quoted reference as the header value:
kong.yaml
deck gateway sync deletes entities missing from the file, so keep the vaults entry in the same file as the plugin.
What you will see in Bronto
Traces
Open Tracing and filter by yourservice.name. Each request is a trace rooted at a kong server span, with one child per phase and plugin, named kong.<phase>.plugin.<plugin-name> — for example kong.access.plugin.key-auth. kong.router, kong.dns and kong.balancer cover routing and the upstream connection.
Only proxied requests reach kong.dns and kong.balancer, which makes those two spans a reliable “did this request reach the upstream?” marker.
Access logs
Filter Search by$log.type = 'access'. Each request is one log record with route, service, consumer, latency and status fields. Two are particularly useful:
$kong.response.source separates a 401 from your upstream from a 401 from key-auth, which the status code alone cannot.
Runtime logs
Filter by$log.type = 'error'. These are Kong’s own log lines, with $introspection.source naming the Lua file that wrote each one. Lines written during a request carry its trace and span IDs.
Metrics
With every family enabled, Kong emits 14 metrics, includinghttp.server.request.count, http.server.request.size, http.server.response.size, kong.latency.total, kong.latency.upstream and kong.latency.internal, plus gateway health under kong.nginx.*, kong.shared_dict.* and kong.memory.workers.lua_vm.
http.server.request.count carries kong.response.source, http.response.status_code, kong.route.name and kong.service.name as attributes, so rejections can be counted by route and status without querying logs.
Kong exports metrics as cumulative. Bronto accepts cumulative and recommends delta; to convert, send metrics.endpoint to an OpenTelemetry Collector running the cumulativetodelta processor and forward from there to Bronto.
AI Gateway
On routes that useai-proxy, Kong also records token usage, model, cost and LLM latency for every call. Turn on statistics in the plugin:
kong.yaml
log_statistics: true is what adds the AI fields to the access log — without it there is no token telemetry. log_payloads: false keeps prompt and completion text out of Bronto. input_cost and output_cost are your model’s price per million tokens; until they are set, $ai.proxy.usage.cost reports 0.
The fields arrive on the same access log records:
Group by
$kong.auth.consumer.username to see token use and spend per tenant.
Troubleshooting
- No metrics? Check the
metrics.enable_*flags. With all of themfalse— the default — the metrics endpoint receives nothing. - No spans?
KONG_TRACING_INSTRUMENTATIONSmust be set on the data plane, not only the plugin. The plugin’ssampling_rateandKONG_TRACING_SAMPLING_RATEboth apply. - Error-rate panels on spans read zero. Kong leaves
$span.status_codeasSTATUS_CODE_UNSETon rejected requests, including 401s and 429s. Build rejection panels on$http.response.status_codeor$kong.response.sourceinstead. kong.access.plugin.opentelemetryspan missing on some requests. Expected: the plugin has a low access-phase priority, so its own span is absent whenever an earlier plugin rejects the request.- AI fields missing from access logs? Set
logging.log_statistics: trueonai-proxy. - Need to see exactly what Kong sends? Point the four endpoints at an OpenTelemetry Collector with the
debugexporter atverbosity: detailed, then read the Collector’s output for span names, attribute keys and metric temporality.
For assistance or questions, contact support@bronto.io.
