nginx 中 map 指令通过构建变量配合 access_log 的 if 条件实现按请求特征控制日志记录、格式及输出位置,或在 log_format 中嵌入变量以增强日志内容。

在 Nginx 中,map 指令本身不直接记录日志,但它可以配合 log_format 和 access_log 实现**按条件控制日志是否写入、或写入不同格式/位置**。核心思路是:用 map 构建一个变量(如 $loggable 或 $log_level),再在 access_log 指令中通过该变量控制日志行为。
用 map 设置日志开关变量
最常见的是根据请求特征(如 URL、状态码、User-Agent)决定是否记录该请求到特定日志文件。
例如,只对非健康检查请求记录详细日志:
map $request_uri $log_detail {
default 1;
~^/healthz$ 0;
~^/readyz$ 0;
}
<p>server {
access_log /var/log/nginx/access.log main if=$log_detail;</p><h1>其他配置...</h1><p>}</p>说明:
-
map块定义了变量$log_detail:匹配健康检查路径时为0,其余为1; -
access_log ... if=$log_detail表示仅当变量值为非空且非"0"时才写入日志(Nginx 的if=条件判断规则); - 注意:
if=后的变量值若为"0"、空字符串或未定义,日志将被跳过。
用 map 区分日志格式并路由到不同文件
可根据状态码、设备类型等动态选择日志格式,甚至输出到不同文件:
map $status $log_type {
~^[23] "normal";
~^[45] "error";
default "other";
}
<p>log_format normal '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent';
log_format error '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';</p><p>server {
access_log /var/log/nginx/access.log normal if=$log_type;
access_log /var/log/nginx/error_access.log error if=$log_type;</p><h1>注意:两个 access_log 指令可共存,但需确保 if 条件互斥或有意叠加</h1><p>}</p>说明:
- 变量
$log_type根据响应状态码前缀分类; - 两个
access_log指令分别指定了不同格式和文件,并通过相同变量控制——实际中建议让条件互斥(如用~^4和~^5分开),避免重复记录; - 更稳妥做法是用两个独立
map变量,例如$log_normal和$log_error,各自控制一行access_log。
结合 map 和自定义变量实现细粒度日志标记
想在日志中体现“是否为移动端”、“是否含敏感参数”等语义信息,可在 log_format 中直接引用 map 变量:
map $http_user_agent $device_type {
default "desktop";
~*android|ios "mobile";
~*ipad "tablet";
}
<p>map $args $has_token {
~token= "yes";
default "no";
}</p><p>log_format enriched '$remote_addr [$time_local] "$request" $status $device_type $has_token';</p><p>server {
access_log /var/log/nginx/enriched.log enriched;
}</p>说明:
- 两个
map分别提取设备类型和查询参数是否含token=; -
log_format中直接使用这些变量,无需额外条件判断; - 这种方式不控制“是否记录”,而是增强日志内容,便于后续分析或筛选。
注意事项与限制
map 是运行时计算的,性能开销极小,但需注意以下几点:
-
map块必须定义在http块内,不能放在server或location中; -
if=条件仅支持单个变量,不支持表达式(如if=$log_detail+$log_error不合法); - 变量值比较是字符串匹配,
"0"被视为 false,"false"或"off"仍是 true; - 若需复杂逻辑(如多条件 AND/OR),应提前在
map中组合好结果,而不是依赖外部判断。











