Nginx自定义access_log格式必须先用log_format声明命名格式,再在access_log中引用名称;直接拼接字段会报错。常用变量需按阶段使用,如$upstream_response_time依赖proxy_pass,$request_time为总耗时(毫秒浮点),$http_x_forwarded_for需配合real_ip配置才可信;条件日志需用map预定义,不可用if;禁用$request_body等高开销变量,仅保留排障与监控必要字段,并注意日志轮转与浮点精度问题。

Access-Log自定义格式的语法结构必须用log_format定义
直接在access_log指令里拼接字段会报错,Nginx不支持这种写法。所有自定义日志格式必须先用log_format声明一个命名格式,再在access_log中引用名字。
常见错误是把$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent这类字符串直接塞进access_log路径后面,结果Nginx启动失败,报invalid number of arguments in "access_log" directive。
正确做法是:
log_format custom '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';然后在server或location块中启用:
access_log /var/log/nginx/access.log custom;
常用变量含义和实际使用场景差异
不是所有$开头的变量都适合放日志里——有些只在特定阶段可用,比如$upstream_response_time必须有proxy_pass才有效,否则输出短横线-;$request_time记录从接收首字节到发送完响应的总耗时(毫秒级浮点数),而$msec是当前时间戳(秒级带毫秒),别混淆。
-
$http_x_forwarded_for:穿透代理后的真实客户端IP,但不可信,需配合set_real_ip_from和real_ip_header使用 -
$hostvs$http_host:前者取自请求行或Host头(更可靠),后者严格取Host请求头,可能为空或被篡改 -
$request_length:整个请求(含header+body)长度,排查大请求或DoS时有用 -
$bytes_sentvs$body_bytes_sent:前者含响应header大小,后者只算body,监控流量时注意区分
按条件写入不同日志文件需要map+access_log组合
想对API接口单独记日志、或把4xx/5xx错误写进另一个文件?不能靠if判断,Nginx的if在日志上下文中不生效。得用map预计算日志路径或格式名。
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
例如,把所有/api/开头的请求写入独立日志:
map $request_uri $api_log {
~^/api/ "/var/log/nginx/api-access.log";
default off;
}
server {
access_log /var/log/nginx/access.log main;
access_log $api_log api;
}注意:map必须放在http块顶层,不能嵌套在server里;access_log支持多个,会同时写入;值为off表示禁用该条日志。
性能和磁盘风险:高并发下避免写入过多变量
每个变量都要在请求处理末尾实时计算并拼接字符串,像$request_body这种会触发完整body缓存,严重拖慢性能,生产环境绝对禁用;$cookie_xxx、$arg_xxx看似轻量,但若请求带大量query参数或cookie,日志行会爆炸式增长,快速占满磁盘。
建议只保留必要字段:
- 排障刚需:
$remote_addr、$time_local、$request、$status、$request_time - 监控扩展:加
$upstream_response_time(反向代理场景)、$bytes_sent(流量统计) - 敏感信息一律过滤:不记录
$request_body、$args、$cookie_sessionid等
日志轮转和压缩策略得跟上,否则$request_time这种浮点数字段会让日志解析工具更难处理——它输出的是类似0.003或12.987654这种不定长小数,不是整数毫秒。

















