nginx可通过map指令定义日志开关变量,结合log_format和access_log的条件参数实现按需记录:仅当变量值为非空字符串时写入日志,否则完全跳过。

Nginx 本身不支持“运行时条件判断后决定是否写日志”,但可以通过 map 指令 + log_format + access_log 的条件开关 实现等效效果:只对满足特定条件的请求记录日志,其余请求跳过日志写入。
用 map 定义日志开关变量
在 http 块中定义一个变量(如 $loggable),根据请求特征(URI、状态码、Header、IP 等)映射为 "1"(记录)或空字符串(不记录):
map $status $loggable {
~^[23] "1"; # 状态码以 2 或 3 开头的记录(成功/重定向)
default ""; # 其他状态(4xx/5xx)不记录
}
# 或按路径过滤:
map $request_uri $loggable {
~^/api/v1/health ""; # /api/v1/health 不记日志
~^/static/ ""; # 静态资源不记
default "1";
}
定义带条件的日志格式
使用 log_format 定义格式时,可包含该变量,但关键在于下一步——让 access_log 只在变量非空时生效:
log_format conditional '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
在 location 或 server 中按条件启用 access_log
access_log 指令支持第三个参数:当变量值为非空字符串时才写日志。直接引用前面定义的 $loggable:
server {
listen 80;
location / {
# 启用条件日志:仅当 $loggable == "1" 时写入
access_log /var/log/nginx/access.log conditional $loggable;
proxy_pass http://backend;
}
}
- 若
$loggable值为空(""),Nginx 完全跳过该请求的日志写入,不产生空行 - 变量必须在
access_log所在作用域(如 location)中已定义或可继承 - 多个条件可嵌套使用 map(例如先按 URI 过滤,再按状态码二次筛选)
常见实用组合示例
-
只记录错误请求:把
map $status $loggable { ~^[45] "1"; default ""; },配合独立 error_access.log -
排除爬虫和健康检查:用
$http_user_agent或$arg_x_health判断并设为空 -
按客户端 IP 分组采样记录:结合
geo或哈希(map $remote_addr $loggable { ... default "1"; }配合split_clients)实现 1% 日志采样











