nginx通过map+log_if精准记录目标url访问日志,使用$uri字段聚合接口维度热度,配合awk实时统计过滤无效流量。

直接用 access_log 监控特定 URL 的访问热度,核心不是“把所有日志都记下来再筛”,而是让 Nginx 只对目标 URL 记录日志,减少冗余、提升准确性和处理效率。
精准匹配目标 URL,启用条件日志
只记录你关心的路径,比如 /api/v2/order/submit 或 /user/profile,避免混入健康检查、静态资源等干扰项。
用 map 指令标记是否命中,再配合 log_if 控制写入:
map $request_uri $is_target {
~^/api/v2/order/submit 1;
~^/api/v2/user/profile 1;
default 0;
}
log_format target '$time_iso8601 $uri $status $body_bytes_sent $request_time';
access_log /var/log/nginx/target.log target if=$is_target;
这样,只有匹配正则的目标请求才会落盘,日志体积小、后续分析快。
日志格式必须用 $uri,不是 $request_uri
$uri 是解码后、无 query string 的标准路径(如 /api/v2/order/submit),适合按接口维度聚合;$request_uri 带参数和编码(如 /api/v2/order/submit?id=123&token=abc%2Fdef),会把同一接口拆成多个条目,统计失真。
定义日志格式时明确使用 $uri:
log_format hot_uri '$time_iso8601 $uri $status $request_time'; access_log /var/log/nginx/hot_uri.log hot_uri if=$is_target;
用简单命令快速看实时热度
日志写入后,不需要上 ELK,一条 shell 就能查最近一小时最热的 10 个 URL:
awk -v cutoff="$(date -d '1 hour ago' '+%Y-%m-%d %H:%M:%S')" \
'$1 > cutoff {print $2}' /var/log/nginx/hot_uri.log | \
sort | uniq -c | sort -nr | head -10
注意字段序号:$1 是时间(因用了 $time_iso8601),$2 是 $uri —— 先用 head -1 看一眼日志确认字段位置。
过滤噪音,让结果更贴近真实业务
默认统计会包含 404、爬虫、内部探针等无效流量。可在 awk 中叠加过滤:
- 排除非 2xx 状态码:
$3 >= 200 && $3 - 排除已知爬虫 UA(需在日志中记录
$http_user_agent):!/(curl|sqlmap|nuclei|Go-http-client)/ - 排除内部调用 IP(如
10.0.0.0/8):$4 !~ /^10\./
组合示例:
awk '$1 > cutoff && $3 >= 200 && $3 <p>不复杂但容易忽略</p>











