nginx 不支持按日志级别动态分流 access_log,但可通过 map 指令基于状态码、请求头等特征实现条件记录;支持按 status 分级归档、结合 x-debug 参数启用 debug 日志、openresty 中用 lua 做复杂判断,本质是静态规则匹配而非运行时级别控制。

Nginx 本身不支持像应用层那样按“日志级别”(如 debug/info/warn/error)动态分流 access_log,因为 access_log 是访问日志,记录的是 HTTP 请求生命周期的固定字段,没有内置的 severity 字段。但可以通过请求特征(如状态码、路径、响应时间、请求头等)实现**逻辑上的“按需记录”或“分级归档”**,达到类似“动态分流”的效果。
用 map 指令做条件映射
利用 map 指令根据变量(如 $status、$request_time、$arg_debug)生成布尔标记,再在 log_format 或 access_log 指令中引用,控制是否写入某类日志文件。
- 定义一个 map 判断是否为“错误级”请求(如 4xx/5xx):
map $status $is_error {
~^[45] 1;
default 0;
}
- 在 server 块中按条件启用不同 access_log:
access_log /var/log/nginx/access.log main if=$is_error; access_log /var/log/nginx/debug.log debug if=$arg_debug;
注意:if= 后的变量值为 0 时该行日志不记录;非 0 或非空字符串时才写入。
按响应状态码分文件记录
这是最常用也最实用的“分级”方式,把错误请求单独归档,便于监控和排查。
- 为 2xx/3xx、4xx、5xx 分别配置日志路径:
map $status $log_level {
~^2 info;
~^3 info;
~^4 warn;
~^5 error;
}
log_format info '$time_iso8601 [$log_level] $remote_addr "$request" $status $body_bytes_sent';
log_format warn '$time_iso8601 [$log_level] $remote_addr "$request" $status $body_bytes_sent $request_time';
log_format error '$time_iso8601 [$log_level] $remote_addr "$request" $status $body_bytes_sent $upstream_addr $upstream_response_time';
access_log /var/log/nginx/info.log info if=$log_level;
access_log /var/log/nginx/warn.log warn if=$log_level = warn;
access_log /var/log/nginx/error.log error if=$log_level = error;
⚠️ 注意:Nginx 不支持在同一个 location 中对同一变量多次使用 if= 判断,推荐用 map 预先分类后,配合多个 access_log 指令 + 精确匹配值(如 if=$log_level = error)来实现分流。
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
结合自定义请求头或参数做调试级日志
开发或排障时,可通过加 header(如 X-Debug: 1)或 query 参数(如 ?log=debug)临时开启详细日志。
- 启用 debug 日志仅限带特定 header 的请求:
map $http_x_debug $debug_log {
"1" /var/log/nginx/debug.log;
default off;
}
access_log $debug_log debug;
- 或更灵活地组合判断:
map "$http_x_debug:$arg_log" $debug_target {
"1:" /var/log/nginx/debug.log;
":debug" /var/log/nginx/debug.log;
default off;
}
access_log $debug_target debug;
这样既避免全量 debug 日志带来的 I/O 压力,又保留按需开启的能力。
用 Lua 实现更精细的动态决策(OpenResty)
如果已部署 OpenResty,可用 lua 计算复杂条件(如用户角色、接口耗时百分位、响应体关键词),再决定是否记录及写入哪个文件。
- 示例:响应体含 "error" 且耗时 >1s 才记 error 日志:
log_by_lua_block {
local res_body = ngx.ctx.response_body
local rt = tonumber(ngx.var.request_time) or 0
if res_body and res_body:match("error") and rt > 1 then
ngx.log(ngx.ERR, string.format("%s %s %s %s",
ngx.var.time_iso8601, ngx.var.remote_addr,
ngx.var.request_uri, ngx.var.status))
end
}
⚠️ 注意:此方式写入的是 error_log,不是 access_log;如需写入 access_log 文件,需搭配 lua-resty-logger-socket 或异步写文件模块,不推荐高频写磁盘。
不复杂但容易忽略:Nginx 的 access_log 分流本质是“按请求特征做静态规则匹配”,不是运行时日志级别控制。真正需要结构化、多级别、可过滤的日志,建议在 upstream 应用层生成,Nginx 只做原始访问日志采集与初步筛选。










