nginx可通过map指令结合access_log按请求特征动态分流日志,再用logrotate统一归档;需在http块定义map、使用绝对路径、预建目录并赋权,支持ip段、referer、host、路径等多维度分类。

Nginx 本身不直接识别“请求源”(比如来源 IP 段、Referer 域名、User-Agent 类型等)并自动分流日志,但可以通过 map 指令结合 access_log 实现按请求特征动态路由到不同日志文件,再配合 logrotate 完成归档。核心思路是:先分类,再记录,最后轮转。
按真实客户端 IP 段分离日志
适用于区分内网调试流量、CDN 回源、或特定合作方调用。
# 在 http 块中定义映射
map $remote_addr $log_target {
default "common";
~^192\.168\. "internal";
~^10\. "internal";
~^172\.(1[6-9]|2[0-9]|3[0-1])\. "internal";
203.0.113.42 "partner-a";
198.51.100.15 "partner-b";
}
# 定义对应日志格式(可选)
log_format internal_log '$time_local | $remote_addr | $request | $status | $body_bytes_sent';
log_format partner_log '$time_local | $http_referer | $http_user_agent | $request | $upstream_response_time';
# 在 server 或 location 中引用
access_log /var/log/nginx/access-$log_target.log $log_target;
⚠️ 注意:
-
map必须在http块顶层定义,不能嵌套; -
$log_target的值会作为日志文件名的一部分(如access-internal.log),需确保目录可写; - Nginx 不支持运行时创建目录,建议提前建好
/var/log/nginx/internal/等子目录并赋权(如chown nginx:nginx /var/log/nginx/internal); - 若使用相对路径(如
access-$log_target.log),Nginx 会写入配置工作目录(通常是/etc/nginx),应改用绝对路径。
按 HTTP Referer 或 Host 域名分流
适合追踪第三方平台跳转、小程序来源、或灰度域名流量。
map $http_referer $referer_log {
~^https?://(www\.)?taobao\.com "taobao";
~^https?://(www\.)?weixin\.qq\.com "wechat";
~^https?://(www\.)?alipay\.com "alipay";
default "other";
}
map $host $host_log {
~^api-staging\.example\.com "staging";
~^api-beta\.example\.com "beta";
~^api\.example\.com "prod";
default "unknown";
}
# 可组合使用(例如只对 prod 接口记录 referer 分类日志)
location ^~ /v3/ {
access_log /var/log/nginx/api-v3-$referer_log.log main;
}
✅ 提示:
-
$http_referer可被伪造,仅作辅助分析,不可用于安全控制; - 多个
map可叠加,但access_log行只支持一个变量插值,如需复合命名(如v3-wechat-prod.log),需用脚本预生成或改用 Lua 模块(OpenResty); - 日志文件名中避免特殊字符(如
/,:),map正则匹配建议用~^开头确保前缀匹配。
按请求路径前缀 + 来源标识联合归档
常见于微服务网关场景,例如 /payment/* 且来自 app.example.com 的请求单独落盘。
# 先提取 host 和 path 特征
map $host $site_tag {
app.example.com "app";
admin.example.com "admin";
default "other";
}
map $request_uri $path_tag {
~^/payment/ "pay";
~^/user/ "user";
~^/order/ "order";
default "misc";
}
# 组合标识(需在 server 或 location 内用变量拼接)
server {
listen 80;
server_name api.example.com;
location / {
# 构造日志名:access-app-pay.log
set $log_file "access-${site_tag}-${path_tag}.log";
access_log /var/log/nginx/$log_file main;
}
}
? 要求:
-
set指令需在location内,且依赖ngx_http_rewrite_module(默认启用); -
$log_file是运行时变量,Nginx 会按实际值打开对应文件,无需预先创建所有组合文件; - 同一文件可能被多个 worker 进程并发写入,Nginx 自动处理追加,但归档时需统一管理。
归档:用 logrotate 按文件名模式切割
所有按源分离的日志文件,都可通过通配规则统一轮转:
# /etc/logrotate.d/nginx-sources
/var/log/nginx/access-*.log {
daily
missingok
rotate 15
compress
delaycompress
notifempty
create 644 nginx nginx
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
endscript
}
✅ 验证方式:
- 手动触发:
sudo logrotate -f /etc/logrotate.d/nginx-sources; - 查看是否生成
access-internal.log.1.gz等归档文件; - 检查
nginx进程是否仍在向新access-internal.log写入(tail -f /var/log/nginx/access-internal.log)。
不复杂但容易忽略权限和路径一致性。











