Skip to main content

syslog

The syslog plugin sends APISIX and API7 Gateway request and response logs as JSON objects to syslog servers in batches. It supports TCP, UDP, TLS, and customizable log formats.

Examples​

The examples show how to send gateway request logs to a syslog collector, customize their contents, and conditionally include request bodies.

To follow the examples, prepare a syslog collector:

The pinned rsyslog collector image is published for amd64. Set the running APISIX or API7 Gateway container name:

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

Create a dedicated network:

docker network create gateway-rsyslog-net

Connect the gateway to the network:

docker network connect gateway-rsyslog-net "$GATEWAY_CONTAINER"

Start the collector with TCP reception enabled:

docker run -d \
--platform linux/amd64 \
--name rsyslog-collector \
--network gateway-rsyslog-net \
-e ENABLE_TCP=on \
-e ENABLE_UDP=off \
rsyslog/rsyslog-collector:2026-04

Set the collector hostname used by the APISIX Admin API and ADC examples:

export SYSLOG_HOST=rsyslog-collector

In a separate terminal, follow logs received by the collector:

docker exec rsyslog-collector tail -f /var/log/all.log

Send Logs to a Syslog Server​

The following example enables the syslog plugin on a route and sends logs for matching requests to the collector.

Create a route with syslog as follows:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "syslog-route",
"uri": "/anything",
"plugins": {
"syslog": {
"host": "$SYSLOG_HOST",
"port": 514,
"flush_limit": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}
EOF

❶ Configure the collector hostname reachable from the gateway.

❷ port: replace with the port of your syslog server.

❸ flush_limit: set to 1 to push logs to the syslog server immediately.

Send a request to the route:

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

You should receive an HTTP/1.1 200 OK response.

The collector prefixes each received line with syslog metadata. The JSON message should be similar to the following:

{
"upstream": "100.31.16.17:80",
"service_id": "",
"client_ip": "192.168.155.1",
"response": {
"headers": {
"date": "Mon, 21 Sep 2026 09:44:46 GMT",
"content-type": "application/json",
"access-control-allow-origin": "*",
"server": "APISIX/3.18.0",
"access-control-allow-credentials": "true",
"connection": "close",
"content-length": "399"
},
"size": 627,
"status": 200
},
"start_time": 1789983884322,
"apisix_latency": 650.00001144409,
"latency": 1513.0000114441,
"upstream_latency": 863,
"request": {
"size": 85,
"uri": "/anything",
"headers": {
"x-forwarded-proto": "http",
"user-agent": "curl/8.7.1",
"accept": "*/*",
"host": "127.0.0.1:9080",
"x-forwarded-port": "9080",
"x-forwarded-host": "127.0.0.1:9080"
},
"querystring": {},
"url": "http://127.0.0.1:9080/anything",
"method": "GET"
},
"route_id": "syslog-route",
"server": {
"version": "3.18.0",
"hostname": "dd2886d0b7bf"
}
}

Add Fields With Plugin Metadata​

The following example uses plugin metadata and built-in variables to add selected request and response fields to syslog instances that do not define their own log_format_extra.

Create a route with the syslog plugin:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "syslog-route",
"uri": "/anything",
"plugins": {
"syslog": {
"host": "$SYSLOG_HOST",
"port": 514,
"flush_limit": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}
EOF

Configure plugin metadata for syslog:

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/syslog" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"log_format_extra": {
"host": "$host",
"@timestamp": "$time_iso8601",
"route_id": "$route_id",
"client_ip": "$remote_addr",
"resp_content_type": "$sent_http_Content_Type"
}
}'

Send a request to the route:

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

In the collector log, the JSON message should include fields similar to the following:

{
"@timestamp": "2026-04-17T05:39:46+00:00",
"resp_content_type": "application/json",
"host": "127.0.0.1",
"route_id": "syslog-route",
"client_ip": "192.168.155.1"
}

Log Request Bodies Conditionally​

The following example includes request bodies only when a query parameter satisfies a configured expression.

Create a route with the syslog plugin as follows:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "syslog-route",
"uri": "/anything",
"plugins": {
"syslog": {
"host": "$SYSLOG_HOST",
"port": 514,
"flush_limit": 1,
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}
EOF

❶ include_req_body: set to true to include request body.

❷ include_req_body_expr: only include request body if the URL query string log_body is yes. In YAML-based configurations, quote "yes" to avoid YAML converting it to a boolean.

Send a request to the route with a URL query string satisfying the condition:

curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST \
-H "Content-Type: application/json" \
-d '{"env":"dev"}'

You should see the request body logged:

{
"upstream": "52.71.230.193:80",
"service_id": "",
"client_ip": "192.168.155.1",
"response": {
"headers": {
"date": "Mon, 21 Sep 2026 09:19:41 GMT",
"content-type": "application/json",
"access-control-allow-origin": "*",
"access-control-allow-credentials": "true",
"server": "APISIX/3.18.0",
"connection": "close",
"content-length": "543"
},
"size": 771,
"status": 200
},
"start_time": 1789982377612,
"apisix_latency": 2.0000038146973,
"latency": 3921.0000038147,
"upstream_latency": 3919,
"request": {
"size": 164,
"body": "{\"env\":\"dev\"}",
"uri": "/anything?log_body=yes",
"headers": {
"x-forwarded-port": "9080",
"content-type": "application/json",
"x-forwarded-proto": "http",
"user-agent": "curl/8.7.1",
"accept": "*/*",
"host": "127.0.0.1:9080",
"x-forwarded-host": "127.0.0.1:9080",
"content-length": "13"
},
"querystring": {
"log_body": "yes"
},
"url": "http://127.0.0.1:9080/anything?log_body=yes",
"method": "POST"
},
"route_id": "syslog-route",
"server": {
"version": "3.18.0",
"hostname": "dd2886d0b7bf"
}
}

Send a request to the route without any URL query string:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{"env":"dev"}'

You should not observe the request body in the log.

info

The log_format_extra field shown above preserves the default log entry, including request and response bodies collected by the plugin. If you configure log_format instead, include the corresponding variables explicitly:

{
"include_req_body": true,
"include_resp_body": true,
"log_format": {
"request_body": "$request_body",
"response_body": "$resp_body"
}
}

Body size limits still apply. Use log_format_extra to add custom fields without replacing the default log entry.