Nginx 不支持 access_log 中直接使用 if 指令,需通过 map 构造布尔变量配合 access_log if= 参数实现条件日志;状态码过滤与采样(如 4xx/5xx 记录、200 响应 1% 采样)须依赖 $status、$msec 等变量及正则匹配,原生不支持算术运算或字符串截取。

Access log 的 if 指令本身并不存在于标准 Nginx 的 log_format 或 access_log 语法中。你可能混淆了 Nginx 的两个不同机制:条件日志记录(conditional logging) 和 日志格式中的变量(如 $status)。
真正可用的方式:用 map + access_log 的 if 参数实现状态码采样
Nginx 1.7.0+ 支持在 access_log 指令后添加 if= 条件,但该条件只能引用一个布尔型变量(如由 map 指令定义)。因此,要按状态码采样(例如只记录 404、500 或随机 1% 的 200),必须先用 map 构造出符合条件的标志变量。
示例:仅记录 4xx 和 5xx 错误响应
map $status $log_if_error {
~^[45] 1; # 匹配以 4 或 5 开头的状态码(如 404、500、502)
default 0;
}
<p>server {
access_log /var/log/nginx/error_only.log main if=$log_if_error;
...
}实现“采样”:按比例记录特定状态码(如 10% 的 200 响应)
利用 Nginx 内置变量 $request_id(或 $msec、$connection)配合哈希取模,可实现伪随机采样。注意:这不是加密安全的随机,但对日志采样足够稳定。
示例:仅记录约 5% 的 200 响应
将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。
map $status $log_if_200_sample {
200 $log_200_sample_flag;
default 0;
}
<p>map $request_id $log_200_sample_flag {
~^(?:[0-9a-f]{8}-){3}[0-9a-f]{12}$ 0; # 防止空 request_id 干扰(可选)
default 0;
}</p><h1>利用 $msec 小数点后三位做简单哈希(更轻量)</h1><p>map $msec $sample_5_percent {
~.([0-4])$ 1; # 小数点后第一位是 0–4 → 约 50%?需调整
default 0;
}</p><h1>更准确的 5%:用 $connection 取模(连接数相对均匀)</h1><p>map $connection $sample_5_percent_conn {
~^[0-9]+$ $conn_mod;
}</p><p>map $connection $conn_mod {
~^([0-9]+)$ $(${1}%20==0); # Nginx 不支持算术表达式,此写法无效 → 改用第三方模块或 Lua 不现实
}</p><h1>✅ 推荐做法:用 $remote_addr 哈希后取模(稳定且无需额外模块)</h1><p>map $remote_addr $sample_5_percent {
default 0;
~. 1; # 占位,实际靠 split_clients 或更可靠方式
}</p><h1>✔ 实际推荐(简洁可靠):</h1><p>map $status $log_200_5pct {
200 $sample_flag_200;
default 0;
}</p><p>map $request_id $sample_flag_200 {
"~^[0-9a-f]{32}$" $(${1:0:1}%20==0); # ❌ Nginx map 不支持字符串截取和运算
}
⚠️ 关键限制:Nginx 原生 map 不支持字符串切片、数学运算或哈希函数。所以“精确百分比采样”需换思路:
- 用 split_clients(仅适用于变量赋值,不直接用于日志) —— 不适合日志条件
- 用 Lua(via lua-resty-logger-socket 或 log_by_lua) —— 灵活但增加依赖
- 用 $request_id 或 $msec 做简单末位判断(够用)
✅ 实用方案(无 Lua):基于 $msec 小数点后两位做 1% 采样
map $msec $sample_1pct {
~\.(\d{2})$ $1;
}
<p>map $sample_1pct $log_if_200_1pct {
"00" 1;
default 0;
}</p><p>map $status $log_if_status_200 {
200 $log_if_200_1pct;
default 0;
}</p><p>access_log /var/log/nginx/200_sample.log main if=$log_if_status_200;
说明:$msec 格式为 1712345678.123,正则 ~\.(\d{2})$ 提取小数点后两位(如 12),再用 map 匹配是否为 "00" → 理论概率 ≈ 1%(因毫秒小数部分均匀分布)。
组合多个条件:比如“记录所有 500 + 1% 的 200”
用 map 多级嵌套或合并逻辑:
map $status $log_500_or_sampled_200 {
500 1;
200 $sampled_200_flag;
default 0;
}
<p>map $msec $sampled_200_flag {
~.00$ 1;
default 0;
}</p><p>access_log /var/log/nginx/combined_sample.log main if=$log_500_or_sampled_200;
验证与调试技巧
- 临时加一条
log_format debug '$status $msec $request_id'; access_log /tmp/debug.log debug;查看原始值 - 用
curl -I http://your.site/触发不同状态码,检查日志是否按预期出现 - 注意:
if=是在日志写入前判断,不影响响应流程,也不影响其他指令(如 return、rewrite) - 确保
map块放在http块顶层,不能在server内

















