nginx 不原生支持 access_log_if 指令,需通过 map 指令构建布尔变量并配合 access_log if= 参数实现条件日志;map 必须在 http 块顶层定义,且 nginx ≥ 1.7.0 才支持该语法。

AccessLogIf 指令在 Nginx 中是否原生支持
不支持。Nginx 官方核心模块从始至终没有 access_log_if 或 access_log_if 指令,这是常见误解的源头。你看到的“Access-Log-If”其实是社区广泛使用的非官方说法,指代的是通过 map + access_log 的条件变量组合实现的间接过滤——不是语法糖,而是配置技巧。
用 map 构建状态码过滤开关
核心思路是:把 $status 映射为一个布尔型变量(如 $loggable),再把这个变量作为 access_log 的第三个参数(log condition)。Nginx 会跳过值为 0、""、"0" 或未定义的请求日志记录。
示例配置:
map $status $loggable {
default 0;
404 1;
500 1;
502 1;
503 1;
504 1;
}
server {
access_log /var/log/nginx/access.log main if=$loggable;
# 其他配置...
}
-
map必须定义在http块顶层,不能放在server或location内 -
if=$loggable中的$loggable值为0或空时,该请求完全不写入日志(包括时间、连接等基础字段) - 注意不要写成
if= $loggable(带空格),这会导致 Nginx 启动失败并报错:invalid number of arguments in "access_log" directive
为什么不能直接用 if($status >= 500) { ... }
Nginx 的 if 指令在 log 上下文中不可用,且 if 本身在 server 和 location 块中语义受限、易出错,官方明确不建议用于逻辑判断。试图这样写会触发配置错误:
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
# ❌ 错误:if 不允许出现在 access_log 上下文
access_log /path/log if ($status >= 500);
# ❌ 错误:if 在 server 块中不能嵌套 access_log
if ($status ~ "^5") {
access_log /path/log;
}
更关键的是:$status 是响应阶段变量,在 access_log 执行时才可用;而 if 判断发生在请求处理早期,此时 $status 还未生成,恒为 0 —— 所有请求都会被误判为 “不满足条件”。
性能与兼容性注意事项
这种 map 方式几乎无性能损耗:映射在编译期构建查找表,运行时是 O(1) 字符串匹配;但要注意几个边界点:
- Nginx ≥ 1.7.0 才支持
access_log ... if=语法,低于该版本会报错:unknown directive "if=" -
$status只反映 upstream 返回的状态码;如果请求被 Nginx 自身拒绝(如 400、403、413),它仍能正确捕获 - 若同时使用多个
access_log行(例如分别记录 error-only 和 all),每个都需独立声明if=条件,不能共用一个map变量名覆盖逻辑
真正容易被忽略的是:日志采样后,$request_time、$upstream_response_time 等变量依然参与计算和格式化,只是最终不落盘——这意味着高并发下无效日志的格式化开销仍在,只是省了 I/O。如果要极致降载,得配合 log_format 精简字段,而非只靠 if= 过滤。










