Export Request Traces to ClickHouse
AISIX gateways export request traces over OTLP/HTTP. You can send those traces directly to a ClickStack ingestion endpoint or run an OpenTelemetry Collector that writes them to an existing ClickHouse database.
Choose an Ingestion Path
Choose the path that matches the ClickHouse service you operate:
| Destination | Path |
|---|---|
| ClickStack | Send traces to the OTLP/HTTP endpoint supplied by ClickStack. Its packaged Collector handles batching, schema management, and ClickHouse writes. Skip to Configure the AISIX Exporter. |
| Existing ClickHouse database | Deploy the custom Collector configuration in this guide. The Collector receives traces from AISIX and writes them with the ClickHouse exporter. |
For ClickStack, use the complete traces endpoint and authentication header shown by your deployment. A ClickStack OTLP/HTTP endpoint normally ends in /v1/traces. Self-managed ClickStack can use an ingestion key or OIDC bearer token, depending on how its packaged Collector is configured. See the ClickStack Collector guidance for the deployment options.
The remaining Collector deployment steps are for an existing ClickHouse database that does not already expose a suitable OTLP endpoint:
Prerequisites
Before deploying the custom Collector path, prepare the following:
- An AISIX Enterprise or AISIX Cloud environment with an attached gateway, or an AISIX OSS deployment that loads a declarative
resources.yamlfile. - An existing ClickHouse database and a write account. Decide whether the Collector may create its database and tables.
- A working request through the gateway for verification.
- Network access from the gateway to the Collector and from the Collector to ClickHouse.
- Docker Compose or access to the Kubernetes namespace where the gateway runs.
This guide pins OpenTelemetry Collector Contrib 0.163.2. The ClickHouse exporter is included in that distribution, and its v0.163.0 component reference classifies traces support as beta. Review its stability and configuration before using it for production telemetry.
Configure the Collector
The complete configuration below is for a new dedicated Collector. If you already operate a compatible Collector, merge these component definitions and pipeline references into its configuration without replacing unrelated components, then use its normal rollout process.
Create a working directory:
mkdir aisix-clickhouse
cd aisix-clickhouse
Create the following complete Collector configuration and replace the uppercase placeholders:
extensions:
bearertokenauth:
token: 'COLLECTOR_TOKEN'
receivers:
otlp:
protocols:
http:
endpoint: '0.0.0.0:4318'
auth:
authenticator: bearertokenauth
exporters:
clickhouse:
endpoint: 'tcp://CLICKHOUSE_HOST:9000?dial_timeout=10s'
username: 'CLICKHOUSE_USER'
password: 'CLICKHOUSE_PASSWORD'
database: 'TARGET_DATABASE'
traces_table_name: 'TARGET_TRACES_TABLE'
create_schema: true
sending_queue:
num_consumers: 10
batch:
min_size: 5000
flush_timeout: 5s
service:
extensions: [bearertokenauth]
pipelines:
traces:
receivers: [otlp]
exporters: [clickhouse]
Replace the placeholders as follows:
| Placeholder or field | Value |
|---|---|
COLLECTOR_TOKEN | A long random token. For example, generate one with openssl rand -hex 32. Use the same value in the AISIX exporter header. |
CLICKHOUSE_HOST and port 9000 | The ClickHouse native endpoint reachable from the Collector. Use the port and TLS settings supplied by your database operator. |
CLICKHOUSE_USER and CLICKHOUSE_PASSWORD | A ClickHouse account that can insert traces and, when schema creation is enabled, create the target database and tables. |
TARGET_DATABASE | The database that stores the trace table, such as aisix. |
TARGET_TRACES_TABLE | The trace table name, such as otel_traces. |
create_schema | Keep true to let the exporter create a compatible database and table. Set it to false only after your database operator creates a schema compatible with this exporter version. |
The endpoint in this example uses the ClickHouse native protocol without TLS. Configure the exporter's TLS settings when traffic crosses an untrusted network or your database requires TLS. Keep credentials out of source control.
The internal sending_queue.batch block follows the ClickHouse exporter's current batching recommendation. It flushes a partial batch after five seconds, so low-volume verification does not wait for 5,000 rows. Do not add the standalone batch processor for this pipeline.
The queue is in memory and can lose pending traces if the Collector restarts. For restart durability, configure sending_queue.storage with a storage extension, add that extension to service.extensions, and mount its directory on durable storage.
Deploy the Collector
Both examples run the Collector beside the gateway and make the OTLP/HTTP receiver available as otel-collector:4318.
- Docker Compose
- Kubernetes
Find the gateway container and its Docker networks:
docker ps --format 'table {{.Names}}\t{{.Image}}'
docker inspect GATEWAY_CONTAINER --format '{{json .NetworkSettings.Networks}}'
Replace GATEWAY_CONTAINER with the container name returned by docker ps. Select a user-defined network attached to the gateway. Create the following file beside collector.yaml, then replace GATEWAY_NETWORK with that network name:
services:
otel-collector:
image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.163.2
command: ['--config=/etc/otelcol-contrib/config.yaml']
volumes:
- ./collector.yaml:/etc/otelcol-contrib/config.yaml:ro
networks: [gateway]
restart: unless-stopped
networks:
gateway:
external: true
name: GATEWAY_NETWORK
Validate the configuration, start the Collector, and inspect its logs:
docker compose run --rm otel-collector validate --config=/etc/otelcol-contrib/config.yaml
docker compose up -d
docker compose logs --tail=100 otel-collector
The gateway can now reach the receiver at http://otel-collector:4318/v1/traces. Ensure the selected network also lets the Collector reach ClickHouse.
Deploy the Collector in the gateway namespace so the gateway can resolve the short Service name. Replace every GATEWAY_NAMESPACE value below with that namespace.
Create a Secret from collector.yaml:
kubectl -n GATEWAY_NAMESPACE create secret generic otel-collector-config \
--from-file=collector.yaml=./collector.yaml
This Secret contains the ClickHouse password and Collector token. Restrict access with your cluster's normal Secret and RBAC controls.
Create the Collector Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector
namespace: GATEWAY_NAMESPACE
spec:
replicas: 1
selector:
matchLabels:
app: otel-collector
template:
metadata:
labels:
app: otel-collector
spec:
containers:
- name: collector
image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.163.2
args: ['--config=/etc/otelcol-contrib/collector.yaml']
ports:
- name: otlp-http
containerPort: 4318
volumeMounts:
- name: config
mountPath: /etc/otelcol-contrib
readOnly: true
volumes:
- name: config
secret:
secretName: otel-collector-config
Apply the Deployment and expose its receiver:
kubectl apply -f collector-deployment.yaml
kubectl -n GATEWAY_NAMESPACE expose deployment otel-collector \
--name=otel-collector --port=4318 --target-port=4318
kubectl -n GATEWAY_NAMESPACE rollout status deployment/otel-collector
kubectl -n GATEWAY_NAMESPACE logs deployment/otel-collector --tail=100
The gateway can now reach the receiver at http://otel-collector:4318/v1/traces. Allow gateway-to-Collector and Collector-to-ClickHouse traffic in the applicable NetworkPolicies.
If you deploy the Collector in another namespace, use its namespace-qualified Service address. For the OpenTelemetry Collector Helm chart, merge these component settings into its config value rather than the AISIX chart values.
These deployment examples use one Collector replica and do not set resource limits. Size the Collector, queue, and availability model for your trace volume before using this path in production.