Skip to main content
Kong Gateway’s 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_endpoint field in place of access_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
Set <REGION> to eu or us, export DECK_BRONTO_API_KEY, then apply it:
Things to know about this block:
  • 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 flat access_logs_endpoint field is deprecated from 3.14.
  • An endpoint alone exports no metrics. Every enable_* flag defaults to false. Two more exist: enable_ai_metrics adds AI Gateway metrics, and enable_principal_attribute (3.16+) tags metrics with the authenticated principal. push_interval defaults to 60 seconds.
  • service.name and service.namespace select the log dataset and collection. Traces and metrics don’t belong to a dataset; they appear in Explore Traces and Metric Explorer under the same service.name.
  • http_response_header_for_traceid returns 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 of kong.yaml. decK only exposes variables with the DECK_ 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.
  1. Plugin scope: choose Global to cover every service and route.
  2. 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.
  3. 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.name and service.namespace
    • HTTP response header for TraceID: X-Trace-Id
    • Sampling rate: 1
  4. Select View configuration to check the result against the YAML above, then Save.
The data plane environment variables in the first step are still set where the data plane runs; the plugin form does not replace them.

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.
Store the Bronto API key as the secret, then use Look up key in vault on the header value. The field becomes a reference of the form {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 your service.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, including http.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 use ai-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 them false — the default — the metrics endpoint receives nothing.
  • No spans? KONG_TRACING_INSTRUMENTATIONS must be set on the data plane, not only the plugin. The plugin’s sampling_rate and KONG_TRACING_SAMPLING_RATE both apply.
  • Error-rate panels on spans read zero. Kong leaves $span.status_code as STATUS_CODE_UNSET on rejected requests, including 401s and 429s. Build rejection panels on $http.response.status_code or $kong.response.source instead.
  • kong.access.plugin.opentelemetry span 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: true on ai-proxy.
  • Need to see exactly what Kong sends? Point the four endpoints at an OpenTelemetry Collector with the debug exporter at verbosity: detailed, then read the Collector’s output for span names, attribute keys and metric temporality.

For assistance or questions, contact support@bronto.io.