Skip to main content
Version: 3.17

rocketmq-logger

描述#

rocketmq-logger 插件将请求和响应日志以 JSON 对象批量推送到 RocketMQ 集群,并支持自定义日志格式。

属性#

名称类型必选项默认值有效值描述
nameserver_listarray[string]TrueRocketMQ nameserver 列表。
topicstringTrue要推送数据的目标 topic。
keystringFalse消息的 key。
tagstringFalse消息的 tag。
log_formatobjectFalse以 JSON 键值对形式声明的自定义日志格式,值可以引用 NGINX 变量。也可以通过插件元数据在全局范围内配置日志格式,将应用于所有 rocketmq-logger 插件实例。如果插件实例的日志格式与插件元数据的日志格式不同,插件实例的日志格式优先生效。
timeoutintegerFalse3向上游发送数据的超时时间。
use_tlsbooleanFalsefalse若为 true,则启用 TLS 连接以加密传输。
access_keystringFalseACL 的 Access key。设置为空字符串将禁用 ACL。
secret_keystringFalseACL 的 Secret key。
namestringFalserocketmq logger批处理器中插件的唯一标识符。若使用 Prometheus 监控 APISIX 指标,该名称将以 apisix_batch_process_entries 导出。
meta_formatstringFalsedefaultdefaultorigin收集请求信息的格式。设为 default 以 JSON 格式收集,设为 origin 以原始 HTTP 请求格式收集。
include_req_bodybooleanFalsefalse若为 true,则在日志中包含请求体。注意:若请求体太大而无法保存在内存中,由于 NGINX 的限制,将无法记录。
include_req_body_exprarrayFalselua-resty-expr 表达式数组。当 include_req_body 为 true 时使用,仅当此处表达式求值为 true 时才记录请求体。
include_resp_bodybooleanFalsefalse若为 true,则在日志中包含响应体。
include_resp_body_exprarrayFalselua-resty-expr 表达式数组。当 include_resp_body 为 true 时使用,仅当此处表达式求值为 true 时才记录响应体。
max_req_body_bytesintegerFalse524288大于等于 1日志中记录的最大请求体字节数。超出该值的请求体将被截断。在 APISIX 3.16.0 版本中可用。
max_resp_body_bytesintegerFalse524288大于等于 1日志中记录的最大响应体字节数。超出该值的响应体将被截断。在 APISIX 3.16.0 版本中可用。
batch_max_sizeintegerFalse1000大于 0每批次允许的最大日志条目数。达到该值后,批次将被发送至日志服务。设置为 1 表示立即处理。
inactive_timeoutintegerFalse5大于 0在将批次发送至日志服务前等待新日志的最长时间(秒)。该值应小于 buffer_duration
buffer_durationintegerFalse60大于 0发送批次前允许最早条目存在的最长时间(秒)。
retry_delayintegerFalse1大于等于 0批次发送失败后重试的时间间隔(秒)。
max_retry_countintegerFalse0大于等于 0丢弃日志条目前允许的最大重试次数。

注意:schema 中还定义了 encrypt_fields = {"secret_key"},这意味着该字段将会被加密存储在 etcd 中。具体参考加密存储字段

插件元数据#

也可以通过配置插件元数据来设置日志格式,可用配置如下:

名称类型必选项描述
log_formatobjectFalse以 JSON 键值对形式声明的自定义日志格式,值可以引用 NGINX 变量
max_pending_entriesintegerFalse批处理器中允许的最大未处理条目数。达到此限制后,新条目将被丢弃,直到积压减少。在 APISIX 3.15.0 版本中可用。
IMPORTANT

插件元数据的配置为全局范围生效,将作用于所有使用 rocketmq-logger 插件的路由和服务。

使用示例#

以下示例演示如何在不同场景下配置 rocketmq-logger 插件。

请先启动一个示例 RocketMQ 集群:

docker-compose.yml
version: "3"

services:
rocketmq_namesrv:
image: apacherocketmq/rocketmq:4.6.0
container_name: rmqnamesrv
restart: unless-stopped
ports:
- "9876:9876"
command: sh mqnamesrv
networks:
rocketmq_net:

rocketmq_broker:
image: apacherocketmq/rocketmq:4.6.0
container_name: rmqbroker
restart: unless-stopped
ports:
- "10909:10909"
- "10911:10911"
- "10912:10912"
depends_on:
- rocketmq_namesrv
command: sh mqbroker -n rmqnamesrv:9876 -c ../conf/broker.conf
networks:
rocketmq_net:

networks:
rocketmq_net:

启动容器:

docker compose up -d

稍等片刻,nameserver 和 broker 应相继启动。

创建 TopicTest topic:

docker exec -i rmqnamesrv rm /home/rocketmq/rocketmq-4.6.0/conf/tools.yml
docker exec -i rmqnamesrv /home/rocketmq/rocketmq-4.6.0/bin/mqadmin updateTopic -n rmqnamesrv:9876 -t TopicTest -c DefaultCluster

等待来自已配置 RocketMQ topic 的消息:

docker run -it --name rocketmq_consumer -e NAMESRV_ADDR=localhost:9876 --net host apacherocketmq/rocketmq:4.6.0 sh tools.sh org.apache.rocketmq.example.quickstart.Consumer

稍等片刻,消费者应启动并监听来自 APISIX 的消息:

Consumer Started.

打开新的终端会话,继续以下操作。

note

您可以通过以下命令从 config.yaml 中获取 admin_key 并存入环境变量:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

以不同元日志格式记录日志#

以下示例演示如何在路由上启用 rocketmq-logger 插件,记录客户端请求并推送日志到 RocketMQ,同时了解 defaultorigin 两种元日志格式的区别。

创建带 rocketmq-logger 的路由,将 meta_format 设为 default,将 batch_max_size 设为 1 以立即发送日志条目:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "rocketmq-logger-route",
"uri": "/anything",
"plugins": {
"rocketmq-logger": {
"nameserver_list": [ "127.0.0.1:9876" ],
"topic": "TopicTest",
"key": "key1",
"timeout": 30,
"meta_format": "default",
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

向路由发送请求以生成日志条目:

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

您应看到类似如下的日志条目:

{
"client_ip": "127.0.0.1",
"upstream": "34.197.122.172:80",
"start_time": 1744727400000,
"request": {
"headers": {
"host": "127.0.0.1:9080",
"accept": "*/*",
"user-agent": "curl/8.6.0"
},
"querystring": {},
"size": 86,
"uri": "/anything",
"url": "http://127.0.0.1:9080/anything",
"method": "GET"
},
"route_id": "rocketmq-logger-route",
"apisix_latency": 8.9998455047607,
"upstream_latency": 503,
"latency": 511.99984550476,
"response": {
"size": 617,
"headers": {
"content-length": "391",
"connection": "close",
"date": "Tue, 15 Apr 2025 14:30:00 GMT",
"server": "APISIX/3.15.0",
"content-type": "application/json"
},
"status": 200
},
"server": {
"hostname": "apisix",
"version": "3.15.0"
},
"service_id": ""
}

rocketmq-logger 的元日志格式更新为 origin

curl "http://127.0.0.1:9180/apisix/admin/routes/rocketmq-logger-route" -X PATCH \
-H "X-API-KEY: ${admin_key}" \
-d '{
"plugins": {
"rocketmq-logger": {
"meta_format": "origin"
}
}
}'

再次向路由发送请求以生成新的日志条目:

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

您应看到以原始 HTTP 请求格式呈现的日志条目:

GET /anything HTTP/1.1
host: 127.0.0.1:9080
user-agent: curl/8.6.0
accept: */*

通过插件元数据记录请求和响应头#

以下示例演示如何使用插件元数据和 NGINX 变量自定义日志格式,记录请求和响应中的特定头部信息。

在 APISIX 中,插件元数据用于配置同一插件所有实例的公共元数据字段。当插件在多个资源上启用并需要统一更新元数据字段时非常有用。

注意:若希望通过插件元数据自定义日志格式,meta_format 必须设为 default。若 meta_format 设为 origin,日志条目将保持 origin 格式。

首先,创建带 rocketmq-logger 的路由,将 meta_format 设为 defaultbatch_max_size 设为 1 以立即发送日志条目:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "rocketmq-logger-route",
"uri": "/anything",
"plugins": {
"rocketmq-logger": {
"nameserver_list": [ "127.0.0.1:9876" ],
"topic": "TopicTest",
"key": "key1",
"timeout": 30,
"meta_format": "default",
"batch_max_size": 1
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

接着,为 rocketmq-logger 配置插件元数据,记录自定义请求头 env 和响应头 Content-Type

curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/rocketmq-logger" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"log_format": {
"host": "$host",
"@timestamp": "$time_iso8601",
"client_ip": "$remote_addr",
"env": "$http_env",
"resp_content_type": "$sent_http_Content_Type"
}
}'

向路由发送带有 env 头的请求:

curl -i "http://127.0.0.1:9080/anything" -H "env: dev"

您应看到类似如下的日志条目:

{
"host": "127.0.0.1",
"client_ip": "127.0.0.1",
"resp_content_type": "application/json",
"route_id": "rocketmq-logger-route",
"env": "dev",
"@timestamp": "2025-04-15T14:30:00+00:00"
}

按条件记录请求体#

以下示例演示如何按条件记录请求体。

创建如下带 rocketmq-logger 的路由,仅当 URL 查询参数 log_bodyyes 时才记录请求体:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
"id": "rocketmq-logger-route",
"uri": "/anything",
"plugins": {
"rocketmq-logger": {
"nameserver_list": [ "127.0.0.1:9876" ],
"topic": "TopicTest",
"key": "key1",
"timeout": 30,
"meta_format": "default",
"batch_max_size": 1,
"include_req_body": true,
"include_req_body_expr": [["arg_log_body", "==", "yes"]]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

发送满足条件的带 URL 查询参数的请求:

curl -i "http://127.0.0.1:9080/anything?log_body=yes" -X POST -d '{"env": "dev"}'

您应看到日志中包含请求体:

{
"request": {
"method": "POST",
"body": "{\"env\": \"dev\"}",
"size": 183
}
}

不带 URL 查询参数发送请求:

curl -i "http://127.0.0.1:9080/anything" -X POST -d '{"env": "dev"}'

此时日志中将不包含请求体。

note

若在将 include_req_bodyinclude_resp_body 设为 true 的同时自定义了 log_format,插件将不会在日志中包含请求体或响应体。

解决方法是在日志格式中使用 NGINX 变量 $request_body,例如:

{
"rocketmq-logger": {
"log_format": {"body": "$request_body"}
}
}