如何记录HAProxy代理的TCP连接内容?
需求:在HAProxy日志中完整记录TCP连接的传输内容
环境信息
- 系统:Ubuntu Server 18.04
- Docker版本:19.03.12
- HAProxy镜像版本:2.7.3
- Docker Compose版本:1.27.1
- Docker Compose配置:
services: ftt_tcp_proxy_dev: container_name: ftt_tcp_proxy_dev image: haproxy:2.7.3 ports: - "50000:50000" volumes: - /home/user1/git/ftt_tcp_proxy/dev/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro restart: unless-stopped
初始HAProxy配置
global log stdout format raw daemon defaults mode tcp log global log-format "[%t] Connection on port %fp from ip %ci forwarded to %si:%sp with data x" timeout client 60s timeout client-fin 60s timeout connect 60s timeout server 60s timeout server-fin 60s timeout tunnel 60s frontend server1 bind :50000 default_backend server2 backend server2 server server2 10.10.150.82:50000
测试场景与问题
- 在server2执行监听命令:
nc -nvlkp 50000 - 在server1通过HAProxy连接server2:
nc haproxy01 50000(haproxy01为HAProxy容器所在服务器的DNS记录) - 连接可正常建立并转发内容,但日志仅显示占位符
x
尝试过的配置及问题
首次调整frontend配置:
tcp-request inspect-delay 5s tcp-request content capture req.payload(0,100) len 100同时将log-format中的
x替换为%[capture.req.hdr(0)],但日志仅显示破折号-二次调整配置:
tcp-request content capture req.payload(0,5) len 5此时能成功记录“hello”,但存在局限:
- 内容短于5字符时显示破折号
- 内容长于5字符时仅记录前5个字符
当前临时方案
使用tcpdump记录内容:sudo tcpdump -i any -nn -A port 50000,但希望通过HAProxy配置实现需求
解决方案
HAProxy的TCP内容捕获机制无法自动适配任意长度的payload,因为req.payload(start,end)的结束位置是固定值,且len参数限制了最大捕获长度。可通过以下两种方式优化:
方式1:增大捕获长度并处理空内容
设置足够大的捕获长度(根据业务场景调整,比如1024字节),同时优化日志格式处理空值:
修改frontend配置:
frontend server1 bind :50000 tcp-request inspect-delay 10s # 延长检查延迟,确保捕获完整初始payload tcp-request content capture req.payload(0,1024) len 1024 default_backend server2
修改log-format:
log-format "[%t] Connection on port %fp from ip %ci forwarded to %si:%sp with data %[capture.req.hdr(0),field(-1,'-')]"
%[capture.req.hdr(0),field(-1,'-')]的作用是:若捕获内容为空(显示-),则替换为空字符串,避免日志出现多余破折号- 注意:若payload长度超过1024字节,仍只会记录前1024字节,这是HAProxy TCP捕获的固有限制
方式2:开启trace功能(仅适合调试)
如果是临时调试需求,可开启HAProxy的trace功能,详细记录TCP流内容:
在global段添加:
global log stdout format raw daemon trace level verbosity full output stdout
在frontend段添加:
frontend server1 bind :50000 trace tcp-request content capture all default_backend server2
- 该方式会输出极详细的流数据,包括每个数据包内容,适合调试,不建议生产环境长期开启(会产生大量日志)
额外说明
TCP是流式协议,HAProxy无法自动识别“完整消息”边界,只能捕获初始段数据。如果你的业务协议有明确消息边界(比如固定长度、换行符分隔),可使用req.payload(0,1024,CRLF)这类规则,捕获到第一个换行符为止,自动截断到完整消息。
内容的提问来源于stack exchange,提问作者Kallekutta
相关产品推荐
相关产品推荐

