ngx_stream_core_module仅支持四层日志,需与http模块协同实现统一采集:通过定义兼容的unified日志格式、字段映射(如$protocol/$request_time)、SNI提取及日志管道统一收集,达成语义对齐与联合分析。

ngx_stream_core_module 本身只支持四层(TCP/UDP)流量处理,无法直接记录七层(HTTP/HTTPS)日志,因此“四层与七层日志统一采集”不是靠它单独完成的,而是需要和 http 模块协同设计,通过架构层面的统一入口或日志格式对齐来实现。核心思路是:让四层代理(如 TCP 透传 MySQL、Redis、TLS 流量)和七层服务(HTTP API)输出结构一致、字段可对齐、时间可关联的日志,便于后端统一解析与分析。
明确模块职责边界
nginx 的 stream 和 http 是两个独立上下文,互不感知:
-
stream { ... }处理原始 TCP/UDP 连接,无协议解析能力(不识别 HTTP 方法、Host、URL),只能记录连接级信息(client_addr、server_addr、bytes_sent、session_time 等); -
http { ... }可深度解析 HTTP 报文,记录请求级字段(status、request_time、upstream_response_time、$http_user_agent 等)。
二者不能共用同一个 log_format,但可通过命名约定、字段映射、时间戳对齐等方式达成语义统一。
定义跨层通用日志格式
在 http 和 stream 上下文中分别定义名称相同、字段兼容的 log_format,例如:
# 全局定义(放在 events 块外,两者均可引用)
log_format unified '$time_iso8601\t'
'$remote_addr:$remote_port\t'
'$server_addr:$server_port\t'
'$protocol\t' # stream: tcp/udp; http: "http"/"https"
'$status\t' # stream: 仅对 proxy_pass 到 upstream 且启用 proxy_responses 时可用;http: 原生支持
'$bytes_sent\t'
'$bytes_received\t'
'$session_time\t' # stream: 连接持续时间;http: 可用 $request_time 近似替代
'$upstream_addr\t'
'$upstream_bytes_sent\t'
'$upstream_bytes_received';
说明:
-
$protocol在 stream 中为内置变量(tcp/udp/tls),在 http 中需用 map 构造:map $scheme $protocol { default $scheme; }; -
$status在 stream 中仅当使用proxy_responses并配置了proxy_timeout时,对上游响应做简单状态映射(如 2xx→200),否则建议填“-”或固定值(如“200”); -
$session_time是 stream 原生变量,http 中可用$request_time替代(精度一致,均为秒级浮点); - 所有字段用制表符分隔,方便下游用 awk / Logstash / Fluentd 解析。
四层场景下的日志增强技巧
stream 模块虽无七层解析能力,但可通过以下方式提升日志信息量,拉近与 http 日志的语义距离:
- 对 TLS 流量,启用
ssl_preread on,获取 SNI 域名:$ssl_preread_server_name,可作为 service_name 字段写入日志; - 对 MySQL/Redis 等协议,结合
stream_ssl_preread或外部 L7 代理(如 mysql-proxy、redis_exporter)补充应用层标签,再通过 nginx stream 的set_real_ip_from+real_ip_header传递 X-Service-ID 等自定义标头(需客户端配合或前置 LB 注入); - 使用
access_log /path/to/stream.log unified buffer=64k flush=5s,开启缓冲与定时刷盘,降低 I/O 开销; - 避免在 stream 中使用
log_subrequest on(不支持),也不依赖$request类变量(不存在)。
统一采集落地建议
真正实现“统一采集”,关键不在 nginx 单点配置,而在日志管道设计:
- 将 http 和 stream 的日志输出到不同文件(如
/var/log/nginx/access_http.log和/var/log/nginx/access_stream.log),但使用完全相同的log_format unified; - 用同一套日志收集器(如 Filebeat、Fluent Bit)监控两个文件,打上
log_type: http或log_type: stream标签; - 在日志平台(ES / Loki / Splunk)中,用
log_type区分来源,用共通字段(如remote_addr,time_iso8601,bytes_sent)做联合查询或关联分析; - 对需严格关联的场景(如 TLS 握手后紧接 HTTP 请求),可在 stream 层记录 connection_id(用
$connection),并在 http 层通过map或 Lua 注入同名字段(需共享内存或外部 ID 分发机制),实现会话级追踪。
不复杂但容易忽略。











