Skip to main content

clickhouse-logger

The clickhouse-logger plugin sends request and response logs to ClickHouse in batches. The plugin can write the default gateway log entry or a custom format configured on the plugin instance or in plugin metadata.

Examples

The examples below configure a current ClickHouse server and verify default and custom gateway log formats.

Local evaluation credentials

The examples use an HTTP connection and a fixed local password to keep the workflow reproducible. For production, use TLS, store the ClickHouse password in a secret manager, and keep ssl_verify enabled.

Start ClickHouse with a dedicated database and user. The Docker setup uses a dedicated network so that a running APISIX or API7 Gateway container can reach ClickHouse by container name.

Set GATEWAY_CONTAINER to the name of the running APISIX or API7 Gateway container. Create a dedicated network and connect the gateway to it:

export GATEWAY_CONTAINER=replace-with-gateway-container-name

docker network create gateway-clickhouse-net
docker network connect gateway-clickhouse-net "$GATEWAY_CONTAINER"

Start ClickHouse on the same network and bind its HTTP API to the host loopback interface:

docker run -d \
--name clickhouse-server \
--network gateway-clickhouse-net \
-p 127.0.0.1:8123:8123 \
-e CLICKHOUSE_DB=apisix_logs \
-e CLICKHOUSE_USER=apisix_logger \
-e CLICKHOUSE_PASSWORD=apisix-logger-pass \
-e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 \
--ulimit nofile=262144:262144 \
clickhouse/clickhouse-server:26.8.5.13

Wait until the HTTP API is ready:

until curl -fsS -u "apisix_logger:apisix-logger-pass" \
"http://127.0.0.1:8123/ping" | grep -q "Ok"; do
sleep 2
done

Log Requests in the Default Format

The following example writes the plugin's default request and response log entry to ClickHouse.

Create a table named default_logs in your ClickHouse database with columns corresponding to your log format:

curl "http://127.0.0.1:8123" -X POST -d '
CREATE TABLE apisix_logs.default_logs (
host String,
client_ip String,
route_id String,
service_id String,
start_time String,
latency String,
upstream_latency String,
apisix_latency String,
consumer String,
request String,
response String,
server String,
PRIMARY KEY(`start_time`)
)
ENGINE = MergeTree()
' -u "apisix_logger:apisix-logger-pass"

Create a route with clickhouse-logger as follows:

curl "http://127.0.0.1:9180/apisix/admin/routes/clickhouse-logger-route" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"uri": "/anything/clickhouse",
"plugins": {
"clickhouse-logger": {
"user": "apisix_logger",
"password": "apisix-logger-pass",
"database": "apisix_logs",
"logtable": "default_logs",
"endpoint_addrs": ["http://clickhouse-server:8123"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send a request to the route to generate a log entry:

curl -i "http://127.0.0.1:9080/anything/clickhouse"

You should see an HTTP/1.1 200 OK response.

Send a request to ClickHouse to see the log entries:

echo 'SELECT host, client_ip, route_id, start_time FROM apisix_logs.default_logs ORDER BY start_time DESC LIMIT 1 FORMAT PrettyCompactMonoBlock' | \
curl "http://127.0.0.1:8123/?" \
-u "apisix_logger:apisix-logger-pass" \
--data-binary @-

You should see a log entry similar to the following:

┌─host─┬─client_ip─────┬─route_id────────────────┬─start_time────┐
1. │ │ 192.168.155.1 │ clickhouse-logger-route │ 1789560520546 │
└──────┴───────────────┴─────────────────────────┴───────────────┘

Customize Log Format With Plugin Metadata

The following example demonstrates how you can customize log format using plugin metadata.

Create a table named custom_logs in your ClickHouse database with columns corresponding to your customized log format:

curl "http://127.0.0.1:8123" -X POST -d '
CREATE TABLE apisix_logs.custom_logs (
host String,
client_ip String,
route_id String,
service_id String,
`@timestamp` String,
PRIMARY KEY(`@timestamp`)
)
ENGINE = MergeTree()
' -u "apisix_logger:apisix-logger-pass"

Create a route with the clickhouse-logger plugin that is used to forward logs in the specified format to ClickHouse:

curl "http://127.0.0.1:9180/apisix/admin/routes/clickhouse-logger-route" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"uri": "/anything/clickhouse",
"plugins": {
"clickhouse-logger": {
"user": "apisix_logger",
"password": "apisix-logger-pass",
"database": "apisix_logs",
"logtable": "custom_logs",
"endpoint_addrs": ["http://clickhouse-server:8123"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Configure plugin metadata for clickhouse-logger:

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/clickhouse-logger" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"log_format": {
"host": "$host",
"client_ip": "$remote_addr",
"route_id": "$route_id",
"service_id": "$service_id",
"@timestamp": "$time_iso8601"
}
}'

Send a request to the route to generate a log entry:

curl -i "http://127.0.0.1:9080/anything/clickhouse"

You should see an HTTP/1.1 200 OK response.

Send a request to ClickHouse to see the log entries:

echo 'SELECT host, client_ip, route_id, `@timestamp` FROM apisix_logs.custom_logs ORDER BY `@timestamp` DESC LIMIT 1 FORMAT PrettyCompactMonoBlock' | \
curl "http://127.0.0.1:8123/?" \
-u "apisix_logger:apisix-logger-pass" \
--data-binary @-

You should see a log entry similar to the following:

┌─host──────┬─client_ip─────┬─route_id────────────────┬─@timestamp────────────────┐
1. │ 127.0.0.1 │ 192.168.155.1 │ clickhouse-logger-route │ 2026-09-16T12:09:05+00:00 │
└───────────┴───────────────┴─────────────────────────┴───────────────────────────┘