Observability Exporters
Observability exporters send usage events from the gateway to destinations used for tracing, logging, storage, or accounting. This guide configures an OTLP/HTTP exporter through the control-plane path for AISIX Enterprise and AISIX Cloud or the resources-file path for AISIX OSS. It then explains destination choices, content capture, and delivery behavior.
Prerequisites
Before starting, prepare the following:
- One of these configuration paths:
- AISIX Enterprise or AISIX Cloud with an environment, an attached gateway, and a write-scoped admin token. For AISIX Enterprise, follow the AISIX Enterprise getting-started guide. To request AISIX Cloud access, contact API7.
- An open-source AISIX gateway that loads a declarative
resources.yamlfile.
- A telemetry destination for the exporter you plan to use.
- A working model alias and caller API key for delivery verification.
Export the gateway and request values used for verification:
# AISIX_PROXY has no trailing slash or endpoint path
# The local quickstarts use http://127.0.0.1:3000
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export MODEL_ALIAS="YOUR_MODEL_ALIAS"
For the control-plane examples, export the Admin API base URL, admin token, and environment ID:
# AISIX_CP includes /api and has no trailing slash
# The local AISIX Enterprise quickstart uses http://localhost:8080/api
export AISIX_CP="YOUR_AISIX_CONTROL_PLANE_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
In other deployments, use the reachable AISIX Cloud Admin API URL.
Choose an Exporter Kind
All exporter kinds are available through both configuration paths. AISIX Cloud Admin API requests and resource-file entries select a kind with the kind value, and the dashboard shows a label for the same underlying kind:
kind Value | Dashboard Label | Use When |
|---|---|---|
otlp_http | OTLP/HTTP | You already collect traces through an OTLP/HTTP collector or vendor endpoint. |
object_store | Object storage | You want batched NDJSON request events in Amazon S3, S3-compatible storage, Google Cloud Storage, or Azure Blob. |
datadog | Datadog | You use Datadog Logs HTTP intake. |
aliyun_sls | Alibaba Cloud SLS | You use Alibaba Cloud Simple Log Service as the log destination. |
The gateway sends telemetry directly to the selected destination.
Configure an OTLP Exporter
Set the collector endpoint and authorization header used by the example:
# Replace with your values
export OTLP_ENDPOINT="https://collector.example.com/v1/traces"
export OTLP_AUTH_HEADER="Bearer YOUR_COLLECTOR_TOKEN"
The endpoint must be reachable from the gateway process. It can be an https:// or http:// URL with any host, such as an in-cluster collector at http://otel-collector-dev:4318/v1/traces. A receiver running beside a gateway process on the same host can use http://localhost:4318/v1/traces; a containerized gateway needs the receiver's container-network or host address instead. Remove the headers block from the exporter when the receiver does not require authentication.
With http://, the static headers and the exported telemetry cross the network in plaintext. The headers can carry an authorization token and the telemetry can include prompt and response content, so use http:// on networks you trust.
Gateways 1.7.0 and earlier accept an operator-configured http:// endpoint only when its host is localhost, 127.0.0.1, or otel-collector. While such a gateway is registered in the environment, the AISIX Cloud Admin API refuses to save an http:// endpoint on any other host with 422 DP_INCOMPATIBLE. Upgrade the environment's gateways to save it.
AISIX Enterprise or AISIX Cloud
Create the exporter and capture its ID:
EXPORTER_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/observability_exporters" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-otlp",
"kind": "otlp_http",
"endpoint": "'"${OTLP_ENDPOINT}"'",
"headers": {
"Authorization": "'"${OTLP_AUTH_HEADER}"'"
},
"sample_rate": 1
}' | jq -r '.observability_exporter.id')
❶ Set static headers only when the OTLP destination requires them. Header values are encrypted at rest and never returned by read operations.
❷ sample_rate: 1 keeps the delivery check deterministic. It is equivalent to omitting the field, which exports every request trace. After verification, lower the value when you need to reduce span volume.
Retrieve the exporter to confirm the stored configuration:
curl -sS "$AISIX_CP/environments/$ENV_ID/observability_exporters/$EXPORTER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN"
You should see a response similar to the following. Reads expose the configured header names through header_keys and confirm stored values through headers_set; the header values themselves are never returned.
{
"observability_exporter": {
"id": "b46a9f5d-6a4d-4bb1-ae2c-4ab1b22f5e80",
"env_id": "0f2f6a1e-9d33-4a8f-9a6e-2a7b6a9c1d2e",
"name": "prod-otlp",
"enabled": true,
"kind": "otlp_http",
"endpoint": "https://collector.example.com/v1/traces",
"header_keys": ["Authorization"],
"headers_set": true,
"sample_rate": 1,
"created_at": "2026-07-22T08:30:00Z",
"updated_at": "2026-07-22T08:30:00Z"
}
}
Keep $EXPORTER_ID for later updates or deletion. Exporters are enabled by default. Set enabled: false to save the resource without sending telemetry. Disabling or deleting an exporter stops its delivery pipeline on each gateway once the configuration change arrives: events already queued are delivered first, and the exporter drops out of the gateway's delivery health report. Re-enabling it starts a fresh pipeline with its counters reset.
AISIX OSS
Add this exporter to observability_exporters in the complete resources file. Environment interpolation keeps the collector token out of the file:
observability_exporters:
- name: prod-otlp
kind: otlp_http
endpoint: ${OTLP_ENDPOINT}
headers:
Authorization: ${OTLP_AUTH_HEADER}
sample_rate: 1
Validate the assembled complete file:
aisix validate --resources resources.yaml
Start or restart the gateway with OTLP_ENDPOINT and OTLP_AUTH_HEADER in its process environment. Reload a running gateway only if those variables are already available to the process. Exporters are enabled by default; add enabled: false to keep the entry without sending telemetry.
Verify OTLP Delivery
A saved exporter confirms only that AISIX accepted its configuration. Verify the OTLP exporter configured above by capturing the request ID that AISIX returns, finding that ID at the destination, and checking the gateway's delivery signal. If you are checking an existing OTLP exporter with sample_rate below 1, temporarily set the rate to 1 so this request cannot be sampled out.
Send one successful request through a working model alias and capture the ID AISIX returns. This remains accurate whether AISIX accepts caller-supplied IDs or generates its own:
export EXPORTER_NAME="prod-otlp"
if TEST_REQUEST_ID=$(
set -o pipefail
curl -fsS -D - -o /dev/null \
-X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer $AISIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${MODEL_ALIAS}"'",
"messages": [{"role": "user", "content": "Reply with: exporter check"}]
}' \
| awk 'tolower($1) == "x-aisix-request-id:" { id = $2; sub(/\r$/, "", id) } END { print id }'
) && test -n "$TEST_REQUEST_ID"; then
export TEST_REQUEST_ID
printf 'request ID: %s\n' "$TEST_REQUEST_ID"
else
unset TEST_REQUEST_ID
printf 'verification request failed or returned no request ID\n' >&2
false
fi
Wait for the exporter to flush the batch, then search your OTLP backend for a span whose aisix.request_id attribute equals $TEST_REQUEST_ID. Finding the span confirms end-to-end delivery: the gateway loaded the exporter, authenticated to the destination when required, and the destination accepted the batch.
For AISIX Enterprise or AISIX Cloud, the exporter row in the environment's Observability view reports whether delivery is healthy and how many batches online gateways have shipped. You can inspect the same per-gateway heartbeat data through the Admin API:
curl -sS "$AISIX_CP/environments/$ENV_ID/dp_nodes" \
-H "Authorization: Bearer $AISIX_TOKEN" \
| jq --arg exporter "$EXPORTER_NAME" \
'[.data[] | select(.status != "offline") | .exporter_health[]? | select(.name == $exporter)]'
After the next heartbeat, at least one online gateway should report delivered_batches greater than zero and last_error: null. The counters reset when a gateway restarts or the exporter configuration changes. A non-null last_error means delivery is currently failing. The historical fields failed_batches and last_failure_unix remain populated after a later success clears last_error.
For an open-source AISIX gateway, confirm success at the destination. If the record does not arrive, check gateway logs for sink delivery failed; retrying or sink delivery dropped.
Understand Delivery Behavior
Every exporter runs its own delivery pipeline: an in-memory queue in front of a worker that batches records and ships them to the destination. The behavior below is fixed and has no configuration.
Records buffer until the batch reaches 100 records or one second passes, whichever comes first.
A destination that refuses a batch transiently — a connection failure, a 429, or a 5xx — is retried on a time budget rather than a fixed number of attempts. The delay starts at 200 milliseconds and doubles up to a 30-second ceiling, and retries continue until 300 seconds after that batch's first attempt. When the budget is spent, the batch is dropped and counted as retries_exhausted in aisix_otlp_fanout_drops_total. A Retry-After header on a 429 or 503 replaces the computed delay, capped at the same 30 seconds, so a destination asking for a longer pause is honored rather than hammered. A budget rather than an attempt count is what lets an exporter survive a receiver outage of a given length: an outage shorter than the budget loses nothing.
While a batch is being retried, new records keep arriving. Each exporter queue holds 8,192 records; when it is full the newest record is refused and counted as queue_full, so the records already queued still have their chance at the destination.
An exporter with full content capture enabled owns its records, prompt and response text included. With content_max_bytes at its default of 131,072, a full 8,192-record queue behind a stalled destination can hold hundreds of megabytes of resident memory. Size content_max_bytes against the gateway's memory limit when you enable full capture on a destination that can stall. See Configure Content Capture.
Interpret OTLP Traces
AISIX exports one connected trace hierarchy per sampled request. See OTLP Trace Reference for span parentage, W3C trace continuation, names, status, semantic-convention attributes, captured content, and resource fields.
Configure Other Exporters
Use another exporter kind when telemetry should go to object storage or a logging service instead of an OTLP trace backend. With AISIX Enterprise or AISIX Cloud, send one of the following objects as the body of POST $AISIX_CP/environments/$ENV_ID/observability_exporters.
Object Storage
For object storage, choose the storage provider, bucket, and key prefix. The default authentication mode uses a credential reference resolved by the gateway:
{
"name": "request-events-s3",
"kind": "object_store",
"provider": "s3",
"bucket": "acme-aisix-events",
"prefix": "ai-gateway",
"region": "us-east-1",
"credential_ref": "acme_s3"
}
Object storage supports Amazon S3, Google Cloud Storage, Azure Blob, and S3-compatible targets. Cloud identity is supported only for S3 or GCS when the gateway has an attached identity that can write to the bucket. Use credential_ref for Azure Blob and for S3-compatible targets that require static credentials.
For an S3-compatible target such as MinIO, Cloudflare R2, or Alibaba Cloud OSS, set the target endpoint explicitly. Without an endpoint, the exporter uses the native AWS S3 endpoint.
endpoint overrides the storage provider's native endpoint, and its meaning follows provider:
provider | What endpoint sets |
|---|---|
s3 | The S3-compatible host to upload to. |
gcs | The Cloud Storage XML API base URL, such as a private endpoint. Uploads use the XML API, so the endpoint must serve it; an emulator that accepts only JSON API uploads, such as the stock fake-gcs-server image, cannot receive objects. It takes precedence over a gcs_base_url in the service-account JSON. |
azure_blob | The Blob service endpoint. |
The value can be an https:// or http:// URL with any host, such as an in-cluster MinIO at http://minio.storage.svc:9000. With http://, the uploaded request events cross the network in plaintext, so use it on networks you trust. Gateways 1.7.0 and earlier accept http:// only for localhost, 127.0.0.1, and a few emulator host names. While such a gateway is registered in the environment, the AISIX Cloud Admin API refuses to save an http:// endpoint on any other host with 422 DP_INCOMPATIBLE. Upgrade the environment's gateways to save it.
endpoint cannot be combined with cloud identity: the AISIX Cloud Admin API rejects the combination, and an open-source AISIX gateway that loads it never uploads and reports a permanent delivery error. The dashboard offers the field for S3-compatible targets, Cloud Storage, and Azure Blob, and hides it when cloud identity is selected.
A gcs endpoint needs gateways at 1.5.0 or later, because earlier gateways ignore it and upload to Google's public Cloud Storage endpoint instead. Every gateway release that AISIX Enterprise and AISIX Cloud support, 1.6.0 or later, honors it. A connected gateway older than 1.6.0 is not checked when you save; upgrade it before relying on the endpoint. See Mixed-Version Behavior.
Alibaba Cloud SLS
Configure the endpoint host, project, log store, and credential reference:
{
"name": "request-events-sls",
"kind": "aliyun_sls",
"endpoint": "ap-southeast-3.log.aliyuncs.com",
"project": "acme-observability",
"logstore": "ai-gateway",
"credential_ref": "acme_sls"
}
Datadog
Configure the Datadog site, service name, tags, and credential reference:
{
"name": "request-events-datadog",
"kind": "datadog",
"site": "datadoghq.com",
"service": "ai-gateway",
"tags": ["team:platform", "tier:prod"],
"credential_ref": "acme_datadog"
}
For the resources-file path, add these entries to observability_exporters:
observability_exporters:
- name: request-events-s3
kind: object_store
provider: s3
bucket: acme-aisix-events
prefix: ai-gateway
region: us-east-1
credential_ref: acme_s3
- name: request-events-sls
kind: aliyun_sls
endpoint: ap-southeast-3.log.aliyuncs.com
project: acme-observability
logstore: ai-gateway
credential_ref: acme_sls
- name: request-events-datadog
kind: datadog
site: datadoghq.com
service: ai-gateway
tags: ["team:platform", "tier:prod"]
credential_ref: acme_datadog
Keep only the destinations you use, then validate the resources file and start or reload the gateway as described for the OTLP example. Verify these exporters with the same request-ID approach used for OTLP: search object-storage and SLS records by request_id, or Datadog logs by aisix.request_id. The Snowflake guide shows how to inspect object-storage output directly.
SLS, Datadog, and object-storage exporters keep destination credentials out of the exporter resource by using credential references or cloud identity. The gateway resolves those credentials locally when it sends telemetry.