动态会话日志记录 ngx_stream_log_module
一、引言
在使用 NGINX Stream 模块处理 TCP/UDP 会话时,我们常常需要记录每次连接的关键指标(如客户端 IP、会话时长、收发字节数等),便于后续的审计、监控和故障排查。ngx_stream_log_module 就是专门为此设计的,它允许你以自定义格式记录 TCP/UDP 会话日志,并提供了缓冲写入和文件描述符缓存等多种优化手段。
本文将以零基础、一步步的方式,带你从环境准备、模块验证,到配置示例、测试验证,再到常见故障排查,全面掌握 ngx_stream_log_module。
二、模块概览
-  
模块名称:
ngx_stream_log_module -  
首次引入:NGINX 1.11.4
 -  
作用:为 Stream(TCP/UDP)会话写入日志,支持自定义格式、日志缓冲、压缩及条件记录。
 -  
核心指令:
log_format:定义日志格式access_log:开启会话日志并指定格式、路径、缓冲、压缩、条件等open_log_file_cache:为带变量的日志路径缓存文件描述符
 
三、典型场景
- 数据库代理审计
记录来自各客户端 IP 的 MySQL/TCP 连接时长和流量,用于安全审计。 - 实时流量监控
对 Redis、Kafka 等服务的 TCP 会话进行统计,监测异常流量突增。 - 故障定位
当下游服务异常时,通过$status、$session_time等指标快速定位问题来源。 
四、先决条件
-  
NGINX 支持 Stream 模块
请确保在编译或安装时包含了--with-stream参数。 -  
确认已编译或加载
ngx_stream_log_modulenginx -V 2>&1 | grep --color stream_log -  
日志目录准备
为防止权限问题,建议提前创建并设置好目录权限:sudo mkdir -p /spool/logs sudo chown nginx:nginx /spool/logs 
五、指令详解
1. log_format
 
log_format name [escape=default|json|none] string ...;
 
- name:日志格式名称,用于 
access_log引用。 - escape:可选 
default(转义控制字符)、json(JSON 专用转义)、none(不转义)。 - string:日志模板,支持内嵌多个变量,如 
$remote_addr、$session_time等。 
内置变量示例:
| 变量 | 含义 | 
|---|---|
$remote_addr | 客户端 IP 地址 | 
$time_local | 本地时间(日志记录时刻) | 
$protocol | 会话使用的协议(如 TCP/UDP) | 
$status | 连接结束状态码(0 表示正常) | 
$bytes_sent | 发送给客户端的总字节数 | 
$bytes_received | 从客户端接收的总字节数 | 
$session_time | 会话时长,单位秒(带毫秒精度) | 
2. access_log
 
access_log path format [buffer=size] [gzip[=level]] [flush=time] [if=condition];
access_log off;
 
- path:日志文件路径,可写死也可包含变量(见 
open_log_file_cache)。 - format:引用 
log_format定义的格式名。 - buffer:启用缓冲写入,单位字节(如 
32k);不超过系统原子写入大小。 - gzip:启用压缩写入,可选 
=1..9压缩级别;需编译时链接 zlib。 - flush:最大刷新间隔(如 
5m),超时或缓冲满后写盘。 - if:条件表达式;当条件为“0”或空字符串时,跳过本次日志记录。
 
3. open_log_file_cache
 
open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
 
- max:缓存的最大文件描述符数量(LRU 关闭最少使用的)。
 - inactive:若某文件在此时长内未被访问,则关闭描述符(默认 10s)。
 - min_uses:在 
inactive时间内最少使用次数,低于则不缓存(默认 1)。 - valid:每隔该时长检查文件名是否仍指向同一文件(默认 60s)。
 
六、配置示例(一步一步)
以下示例演示如何在 Stream 模块中记录会话日志,并对日志性能进行优化。
-  
在
stream { ... }块外全局定义文件描述符缓存stream {# 缓存最多 1000 个文件描述符,20s 不活跃则关闭,文件存在校验 1m,至少访问 2 次才缓存open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;… } -  
定义日志格式
stream {log_format basic '$remote_addr [$time_local] ''$protocol $status $bytes_sent $bytes_received ''$session_time';… } -  
开启会话日志
stream {# 将日志缓冲到 32KB,5 分钟或满缓冲时写盘access_log /spool/logs/nginx-access.log basic buffer=32k flush=5m;… } -  
启用压缩(可选)
stream {# 以 gzip 压缩(级别 2),缓冲同上access_log /spool/logs/nginx-access.log.gz basic gzip=2 buffer=64k flush=5m;… } -  
条件日志(可选)
stream {# 仅记录时长超过 10 秒的会话access_log /spool/logs/long-sessions.log basic if=$session_time\>10;… } 
完整示例整合:
stream {# 1. 文件描述符缓存open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;# 2. 日志格式log_format basic '$remote_addr [$time_local] ''$protocol $status $bytes_sent $bytes_received ''$session_time';# 3. 普通日志:32k 缓冲,5m 刷新access_log /spool/logs/nginx-access.log basic buffer=32k flush=5m;# 4. 压缩日志:64k 缓冲,gzip 2,5m 刷新access_log /spool/logs/nginx-access.log.gz basic gzip=2 buffer=64k flush=5m;# 5. 仅记录长会话(>10s)access_log /spool/logs/long-sessions.log basic if=$session_time\>10;server {listen     3306;      # 例如:MySQL 代理proxy_pass backend:3306;}
}
 
七、测试与验证
-  
重载配置
sudo nginx -t && sudo systemctl reload nginx -  
模拟 TCP 会话
使用openssl s_client或nc建立连接并发送少量数据:# 简单测试:连接后等待 2 秒再关闭 { echo -n ''; sleep 2; } | nc example.com 3306 -  
查看日志
tail -n20 /spool/logs/nginx-access.log应看到类似:
192.168.1.10 [12/May/2025:10:30:00 +0000] tcp 0 0 2.001表示 IP、协议、状态、字节数与时长。
 
八、常见问题与排查
| 问题 | 排查思路 | 
|---|---|
| 日志不生成 | - 确认 access_log 是否在 stream 或 server 上下文中- 检查 NGINX error.log  | 
| 缓冲后长时间未写盘 | - 检查 flush 设置是否过大- 缓冲区是否未满 - 触发重载时会主动写盘  | 
| gzip 日志无法解压 | - 确认 NGINX 编译时已链接 zlib - 使用 zcat 或 gunzip -t 测试 | 
| 带变量路径日志无缓存(频繁打开/关闭) | - open_log_file_cache 是否已配置- min_uses、inactive 参数是否合理 | 
九、最佳实践
- 预分配缓冲:根据日志量合理设置 
buffer,避免频繁写盘。 - 压缩归档:对历史日志使用 gzip,节省磁盘空间,并可随时通过 
zcat查看。 - 文件描述符缓存:当日志路径含变量时,务必开启 
open_log_file_cache,减少系统调用开销。 - 条件记录:对关键会话(如长连接、大流量)单独出日志,便于聚焦排查。
 - 定期清理:通过外部脚本或 logrotate 管理日志文件,避免目录爆满。
 
十、总结
ngx_stream_log_module 为 NGINX Stream 模块提供了灵活、高性能的会话日志能力。
- 从 格式定义、日志输出、缓冲与压缩、到 文件描述符缓存,覆盖了日志记录的全生命周期。
 - 通过 条件记录 与 压缩归档 等功能,兼顾了性能与可用性。
 
掌握本篇内容后,你即可在 TCP/UDP 代理、数据库中间件、微服务网关等各类场景中,轻松实现精准、可扩展的会话日志记录。祝部署顺利,运维轻松!
