$requested_time 已是毫秒级精度,直接使用即可记录客户端从tls握手完成到响应结束的全链路耗时;nginx 1.17.5+默认微秒计时、日志自动截断为三位小数秒(如0.042),无需额外转换,仅需在log_format中引用$ request_time并确保日志收集链路不截断小数位。

要让 Nginx 的 log_format 记录毫秒级的全链路响应时间(即客户端从 TCP 握手开始到连接断开的完整耗时),关键不是直接用 $request_time,而是改用 $upstream_response_time 或更准确的 $msec 配合自定义变量——但注意:$request_time 本身已是毫秒级精度(Nginx 1.17.5+ 默认启用微秒级计时,日志中自动截断为毫秒显示),它记录的就是“请求处理总时间”,即从接收到第一个字节(含 TLS 握手完成)到发送完最后一个字节的时间,已覆盖绝大多数真实链路场景。
确认 Nginx 版本与 $request_time 精度
Nginx 1.17.5 起默认启用高精度计时(--with-http_realip_module 等非必需,但需确保编译时未禁用 clock_gettime)。$request_time 内部以微秒为单位计算,日志格式中默认输出为秒(如 0.123),可通过格式控制显示毫秒:
- 直接使用
$request_time是最简方式,它已包含:TCP 连接建立(不含三次握手耗时)、TLS 握手(若启用 HTTPS)、HTTP 请求接收、后端交互、响应发送全过程 - 若需严格包含 TCP 握手起始点(极少数审计要求),Nginx 原生不提供该字段;可配合
tcp_info模块或内核 trace 工具(如 eBPF)采集,但超出日志配置范畴 - 验证精度:在
log_format中写"rt=$request_time",观察日志是否出现rt=0.001、rt=0.042等三位小数 —— 有则说明毫秒级有效
配置毫秒级 request_time 日志格式
在 http 块中定义 log_format,用 $request_time 并保留三位小数(隐式毫秒):
log_format main_ext '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" urt="$upstream_response_time"';
说明:
-
$request_time自动以秒为单位、三位小数输出(即毫秒级分辨率),无需额外转换 - 避免用
sprintf或 Lua 手动乘 1000 —— 易引入浮点误差且无必要 - 搭配
$upstream_response_time可对比“Nginx 处理耗时”与“后端响应耗时”,快速定位瓶颈
确保日志写入不丢失毫秒精度
部分旧版 Nginx 或日志收集器(如 Filebeat)可能截断小数位。需检查:
- Nginx 配置中
access_log使用上述main_ext格式,且未被其他 location 覆盖 - 日志轮转工具(如 logrotate)不启用压缩或格式化重写
- 若对接 ELK,Logstash 的
grok或 Ingest Pipeline 需匹配浮点数模式,例如:%{NUMBER:response_time:float},而非%{NUMBER:response_time:int}
替代方案:需要更高精度或自定义起点?
若审计强制要求“从 SYN 开始计时”,Nginx 无法满足(OS 层才掌握 SYN 时间)。此时应:
- 用
ss -i或tcpdump + tshark抓包统计单连接 RTT - 在服务端应用层打点(如 Go 的
http.Server.ConnState),记录StateNew到StateClosed时间差 - Nginx 仅能提供可靠、一致、毫秒级的
$request_time—— 它是业界标准的“用户感知延迟”指标











