Apache APISIX tcp-logger 插件实践指南:将请求日志实时推送到 TCP 服务器
【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix
tcp-logger 是 Apache APISIX 提供的一个日志类插件,它把每个经过网关的请求封装成 JSON 对象,通过 TCP 协议推送到外部的日志收集、监控分析系统(如 Logstash、Vector 等)。本文将基于仓库中的官方文档 docs/en/latest/plugins/tcp-logger.md,结合插件源码 apisix/plugins/tcp-logger.lua 与测试用例 t/plugin/tcp-logger.t,完整讲解该插件的全部配置属性、批量发送机制、自定义日志格式(含 Metadata 全局配置)、启用与下线方法,帮助你在真实网关环境中快速接入 TCP 日志链路。
功能概述
tcp-logger插件用于将请求日志数据以 JSON 格式推送到 TCP 服务器。它面向典型的日志管道场景:APISIX 作为 API 网关承载流量,同时把访问日志实时转交给下游的 TCP 服务(例如 Logstash 输入插件、Vector 的socketsource、自研日志采集服务等),从而无需改造上游业务即可获得统一的访问审计与分析数据。
插件支持批量(batch)发送:日志先进入缓冲区,由批量处理器(Batch Processor)聚合后在满足条件时一次性推送给外部 TCP 服务器,避免每条请求都建立一次 TCP 连接带来的开销。由于批量发送存在缓冲,日志到达外部服务器会有一定延迟,触发条件由批量处理器中的定时器控制(默认每5秒刷新一次,或缓冲区积压达到1000条时立即发送)。
从源码看,插件的执行优先级为405(见 apisix/plugins/tcp-logger.lua),属于日志类插件中较高的优先级,确保日志在请求处理链路后期可靠落盘。核心发送逻辑send_tcp_data通过ngx.socket.tcp建立连接、可选执行 TLS 握手、发送序列化后的 JSON 数据并关闭连接(见 send_tcp_data)。
插件属性(Attributes)详解
在 Route、Service 或 Plugin Config 中启用tcp-logger时,可配置以下属性:
| 名称 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
| host | string | 是 | TCP 服务器的 IP 地址或主机名 | ||
| port | integer | 是 | [0,...] | 目标上游端口 | |
| timeout | integer | 否 | 1000 | [1,...] | 向上游发送数据的超时时间(毫秒) |
| log_format | object | 否 | 以 JSON 键值对声明的日志格式,值仅支持字符串;字符串以$为前缀时可引用 APISIX 或 Nginx 变量 | ||
| tls | boolean | 否 | false | 设为true时启用 TLS/SSL 加密发送 | |
| tls_options | string | 否 | TLS 选项(如verify、ssl_verify等) | ||
| include_req_body | boolean | 否 | false | [false, true] | 设为true时在日志中包含请求体 |
| include_req_body_expr | array | 否 | 当include_req_body为true时的过滤表达式,仅当表达式求值为true时才记录请求体,语法基于 lua-resty-expr | ||
| include_resp_body | boolean | 否 | false | [false, true] | 设为true时在日志中包含响应体 |
| include_resp_body_expr | array | 否 | 当include_resp_body为true时的过滤表达式,仅当表达式求值为true时才记录响应体 |
以上属性与插件源码 apisix/plugins/tcp-logger.lua 中的 schema 声明一一对应:host与port是唯二必填项(required = {"host", "port"}),timeout的最小值为 1、默认 1000 毫秒,tls默认false。值得注意的是,插件在check_schema中还会通过core.utils.check_tls_bool对tls做布尔类型校验(见 check_schema)。
属性使用要点
- timeout:控制单次 TCP 连接的超时(毫秒)。它同时作用于连接建立、发送等阶段(
sock:settimeout(conf.timeout),见 send_tcp_data),在目标 TCP 服务不稳定时应适当调大,避免日志线程长时间阻塞。 - log_format:自定义日志字段。值只支持字符串类型;以
$开头的值会被解析为变量引用(如$host、$remote_addr、$time_iso8601),不带$的值按字面常量输出。可用变量包括 APISIX 内置变量(如route_id、service_id、consumer_name等)以及 Nginx 内置变量(如$host、$remote_addr、$request_uri)。 - tls / tls_options:当目标 TCP 服务器启用了 TLS(如 Logstash 的
ssl输入或安全的日志管道)时,将tls设为true。源码中会在连接建立后执行sock:sslhandshake(true, conf.tls_options, false)(见 TLS 握手逻辑),tls_options可传入如verify等握手选项。 - include_req_body / include_req_body_expr:请求体采集的上限为 512 KiB(
MAX_REQ_BODY = 524288,见 apisix/utils/log-util.lua),超长请求体会被截断。include_req_body_expr基于 lua-resty-expr 编写条件表达式,只有条件满足时才把请求体写入日志,可避免记录大体积或敏感请求体。 - include_resp_body / include_resp_body_expr:响应体采集同样有 512 KiB 上限(
MAX_RESP_BODY)。插件通过body_filter阶段调用log_util.collect_body收集响应体(见 body_filter),若响应经过 gzip 等压缩,会在解码后存入日志(相关实现见 collect_body)。
默认日志格式
未配置log_format时,插件通过log_util.get_full_log(见 apisix/utils/log-util.lua)生成完整的默认日志结构,包含请求、响应、时延、路由、上游等维度的信息,形如:
{ "response": { "status": 200, "headers": { "server": "APISIX/3.7.0", "content-type": "text/plain", "content-length": "12", "connection": "close" }, "size": 118 }, "server": { "version": "3.7.0", "hostname": "localhost" }, "start_time": 1704527628474, "client_ip": "127.0.0.1", "service_id": "", "latency": 102.9999256134, "apisix_latency": 100.9999256134, "upstream_latency": 2, "request": { "headers": { "connection": "close", "host": "localhost" }, "size": 59, "method": "GET", "uri": "/hello", "url": "http://localhost:1984/hello", "querystring": {} }, "upstream": "127.0.0.1:1980", "route_id": "1" }各字段含义如下:
request:请求方法、URI、完整 URL、请求头、查询参数与请求大小;response:响应状态码、响应头与响应大小;server:APISIX 实例的版本号与主机名;upstream:实际命中的上游地址;route_id/service_id:命中的路由与关联的服务 ID;client_ip:客户端真实 IP(支持多层代理取真实来源地址);start_time:请求开始时间戳(毫秒);latency/apisix_latency/upstream_latency:总时延、APISIX 自身处理时延与上游时延(毫秒),计算细节见 latency_details_in_ms。
若请求或响应体被采集(include_req_body/include_resp_body生效),对应内容会追加到request.body与response.body字段中。
批量处理器(Batch Processor)机制
tcp-logger依赖 APISIX 的批量处理器来聚合日志、批量推送,避免每条请求都触发一次 TCP 连接。批量处理器通过batch_processor_manager:wrap_schema将以下参数注入到插件 schema(见 apisix/utils/batch-processor-manager.lua 与 batch-processor.lua):
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| name | string | 插件名(如 "tcp logger") | 批量处理器标识 |
| batch_max_size | integer | 1000 | 每个批次最多容纳的日志条数,达到上限立即推送 |
| inactive_timeout | integer | 5 | 缓冲区最大刷新间隔(秒),到期后无论条数多少都推送 |
| buffer_duration | integer | 60 | 批次中最早一条日志的最大存活时长(秒),超时强制处理 |
| max_retry_count | integer | 0 | 发送失败时的最大重试次数 |
| retry_delay | integer | 1 | 重试前的延迟秒数 |
发送触发逻辑是:每 5 秒或缓冲区积压达到 1000 条时自动推送;inactive_timeout建议小于buffer_duration以获得最优的刷新节奏。当batch_max_size设为 1 时,每条日志立即发送(见批量处理器文档 docs/en/latest/batch-processor.md)。
从源码 log 阶段 可以看到发送序列化细节:batch_max_size == 1时对单条日志编码为单个 JSON 对象{},否则编码为 JSON 数组[{}],随后交给send_tcp_data发送。测试用例 t/plugin/tcp-logger.t 也验证了发送失败(不可达主机)时错误信息failed to connect to TCP server: host[...] port[...]会写入 error log,并可配合max_retry_count、retry_delay进行重试。
通过 Metadata 全局配置日志格式
除在插件配置中设置log_format外,还可以通过**插件元数据(Plugin Metadata)**统一配置日志格式:
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| log_format | object | 否 | 以 JSON 键值对声明的日志格式,值仅支持字符串;字符串以$为前缀时可引用 APISIX 或 Nginx 变量 |
注意:插件元数据是全局生效的,一旦配置,会作用于所有使用了
tcp-logger插件的 Route 与 Service。因此适合在团队内统一日志字段规范(如统一时间戳、客户端 IP、主机名字段),个别路由的特殊格式则放到插件自身的log_format中覆盖。
首先从conf/config.yaml中取出 Admin API 密钥并写入环境变量:
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')然后通过 Admin API 配置tcp-logger的元数据:
curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/tcp-logger -H "X-API-KEY: $admin_key" -X PUT -d ' { "log_format": { "host": "$host", "@timestamp": "$time_iso8601", "client_ip": "$remote_addr" } }'配置生效后,推送到 TCP 服务器的日志会被格式化为如下精简结构(route_id由插件自动附加):
{"@timestamp":"2023-01-09T14:47:25+08:00","route_id":"1","host":"localhost","client_ip":"127.0.0.1"}元数据解析逻辑位于 get_log_entry:当插件配置或元数据中存在非空log_format时,走get_custom_format_log生成自定义日志;否则 HTTP 子系统使用get_full_log生成完整日志。字段值以$开头时通过ctx.var取变量(见 gen_log_format / get_custom_format_log)。测试用例 t/plugin/tcp-logger.t 还覆盖了元数据log_format类型错误(应为 object)会被 400 拒绝、以及元数据格式与插件内log_format的优先级行为。
在 Route 上启用插件
以下示例在id=5的 Route 上启用tcp-logger,将日志推送到127.0.0.1:5044(典型 Logstash TCP 输入端口)。示例中还显式设置了batch_max_size: 1让日志即时发送,便于联调观察:
curl http://127.0.0.1:9180/apisix/admin/routes/5 -H "X-API-KEY: $admin_key" -X PUT -d ' { "plugins": { "tcp-logger": { "host": "127.0.0.1", "port": 5044, "tls": false, "batch_max_size": 1, "name": "tcp logger" } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } }, "uri": "/hello" }'生产环境中建议去掉batch_max_size: 1,采用默认批量策略(每 5 秒或每 1000 条推送一次),以降低 TCP 连接频率、提升吞吐。插件同样可以挂在 Service 或 Plugin Config 上,实现"一条配置、多路由复用"。
验证日志输出
启用插件后,向网关发起一次请求:
curl -i http://127.0.0.1:9080/hello此时在目标 TCP 服务器(如 Logstash 或自定义 TCP 监听程序)上即可收到该请求的 JSON 日志。若要快速验证,可在测试环境用nc或socat监听端口观察原始报文,例如:
nc -l 5044日志结构默认为完整格式(见上文"默认日志格式"),包含请求/响应头、时延、路由、上游等信息;若配置了元数据log_format,则输出自定义精简格式。测试用例 t/plugin/tcp-logger.t 进一步覆盖了tls: true的加密发送、include_req_body: true采集请求体(日志中出现"body":"{\"sample_payload\":\"hello\"}")以及include_resp_body: true采集响应体等场景,可作为接入时的行为参考。
删除插件
移除tcp-logger只需从 Route(或 Service)配置中删除对应插件配置块即可。APISIX 会自动热加载新配置,无需重启网关:
curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT -d ' { "methods": ["GET"], "uri": "/hello", "plugins": {}, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'将plugins置为空对象{}后,该 Route 即不再产生 TCP 日志。若此前配置了plugin_metadata/tcp-logger的全局格式,可通过DELETE /apisix/admin/plugin_metadata/tcp-logger删除元数据,恢复各插件自身的默认格式。
典型使用场景与注意事项
- 对接日志管道:将
host/port指向 Logstash(TCP input)、Vector(socket source)等,即可把 APISIX 访问日志接入 ELK/日志平台;需要加密传输时开启tls。 - 统一日志字段:利用元数据
log_format收敛所有 Route 的日志格式,便于下游按@timestamp、client_ip等字段建索引与分析。 - 控制日志体积:默认完整格式包含全部请求/响应头,数据量大;可用
log_format精简字段,或用include_req_body_expr/include_resp_body_expr只对特定请求记录 body。 - 可靠性:发送失败时错误会记录到 error log,并通过
max_retry_count/retry_delay控制重试;批量缓冲意味着日志存在数秒级延迟,对实时性要求极高的场景可将batch_max_size调小(甚至为 1)。 - 限制说明:请求体与响应体采集均存在 512 KiB 上限,超长内容会被截断;
include_resp_body依赖body_filter阶段,需确认该阶段未被其他插件干扰。
总结
tcp-logger是 APISIX 日志生态中面向 TCP 管道的轻量级输出插件:属性简洁(必填仅host与port),支持 TLS 加密、请求/响应体采集、自定义与全局日志格式,并内置批量处理器以平衡吞吐与延迟。结合 apisix/plugins/tcp-logger.lua 的发送实现、apisix/utils/log-util.lua 的日志采集逻辑以及 t/plugin/tcp-logger.t 的行为测试,你可以放心地将它接入自己的日志链路,实现网关流量的低成本、高吞吐采集与分析。
【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考