结论:Nginx慢查询提取必须依赖$request_time(或$upstream_response_time)字段配合精确正则捕获,不能用body_bytes_sent或request模糊判断;需先确认日志含该字段,再用正则提取URL和耗时,最后导出制表分隔数据用于分析。

直接说结论:Nginx 日志里提取“慢查询”,不能靠 body_bytes_sent 或 request 字段模糊判断,必须结合 $request_time(或 $upstream_response_time)字段 + 精确正则捕获,否则会漏掉真实耗时高但返回小的请求(如 500 错误)、或误抓大响应体但极快的静态文件。
确认日志格式是否含 request_time 字段
这是前提,没这个字段,所有后续正则都白搭。打开任意一条 access.log,看是否存在类似 0.842、12.003 这样的毫秒/秒级数字——它通常在 status 后、body_bytes_sent 前,且由 log_format 显式定义:
- 常见格式中它叫
$request_time(单位:秒,三位小数),例如:'$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time $upstream_response_time' - 若你看到的是整数如
1234,那很可能是$msec(毫秒级时间戳),不是耗时,不能用于慢查询识别 - 如果日志里压根没有这类字段,得先改 Nginx 配置,加
$request_time到log_format,再 reload;历史日志无法补全
写能匹配 request_time ≥ 1s 的正则(带捕获)
目标是精准抓出耗时 ≥1 秒的请求行,并把 URL 和耗时一起提出来。别用 .*request_time.* 模糊扫,容易跨行错位或匹配到注释。
假设你的日志行是标准格式:192.168.1.100 - - [02/Jul/2026:15:23:44 +0000] "GET /api/v1/users?id=123 HTTP/1.1" 200 2345 "https://example.com" "curl/7.68.0" 1.234 0.987
- 查找正则:
"([A-Z]+)\s+([^"]+)"\s+\d{3}\s+\d+\s+"[^"]*"\s+"[^"]*"\s+(\d+\.\d{3})\s+ - 说明:
$1是方法(GET/POST),$2是完整 URL,$3是request_time;\s+(\d+\.\d{3})\s+确保只捕获三位小数的耗时,排除msec或其他数字干扰 - 若要只抓 ≥1s 的,把
\d+\.\d{3}换成(?:[1-9]\d*|0)\.\d{3}|[1-9]\d*\.\d{0,2}—— 但实操中更稳的做法是先全量捕获,再用 Sublime 的列选择 + Sort Lines 排序后人工筛 - 务必勾选
Regular Expression和Match Case(避免误匹配大小写混用的字段名)
批量提取 URL + request_time 并导出为制表分隔
用多光标 + 替换,比手动复制快 10 倍,且不依赖插件。
- 先执行上一步的 Find All,确保所有慢请求行都被高亮
- 按
Ctrl+H打开替换面板,勾选Regular Expression - Find What 填和上面一样的正则(含捕获组)
- Replace With 填:
$2\t$3($2是 URL,$3是耗时,中间用制表符分隔) - 点
Replace All,立刻得到干净的两列表格:第一列 URL,第二列耗时 - 后续可粘贴进 Excel 或用 Sublime 自带的
Sort Lines(右键 → Sort Lines → Sort Lines (case sensitive))按耗时倒序排,Remove Duplicate Lines去重看哪些接口最常慢
容易被忽略的坑:request_time 和 upstream_response_time 的区别
很多人以为 $request_time 就是后端真实耗时,其实它包含 Nginx 自身处理时间(SSL 握手、gzip、header 解析等)。真正反映应用层瓶颈的是 $upstream_response_time(如果有 upstream)。
- 若日志中同时存在两个字段(如末尾的
1.234 0.987),第二个才是后端响应时间;此时应把正则里的$3改为$4,并调整捕获位置 - 但注意:
$upstream_response_time在非 proxy_pass 场景下为 “-”,正则需兼容:(\d+\.\d{3}|-),否则会漏掉直连 PHP-FPM 的请求 - 更关键的是:如果 Nginx 配置了多个 upstream(如负载均衡),
$upstream_response_time可能输出多个值(如0.123, 0.456),这种情况下必须切到命令行用awk或grep -oE '[0-9.]{5,}'提取最大值,Sublime 正则难以可靠处理逗号分隔的多耗时


















