ToolkitX
知识库工具箱

日志与监控

access_log、error_log、自定义格式

20min·进阶

01. access_log——记录每个请求

access_log 记录每一个请求的详细信息——谁在什么时间访问了什么资源、返回了什么状态码、传输了多少数据。这些日志是做数据分析、排查问题、安全审计的基础。 默认的 combined 格式挺全的:客户端 IP、时间、请求行、状态码、响应大小、Referer、User-Agent。 自定义 log_format 可以加更多信息:$request_time(请求处理时间)、$upstream_response_time(后端响应时间)、$upstream_addr(后端地址)、$http_x_forwarded_for(真实客户端 IP,在代理后面特别重要)。 access_log 的路径和是否开启可以针对每个 server 或 location 单独设置。off 关掉日志(对健康检查等频繁请求可以关掉减少 IO)。
nginx
# 自定义日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" '
                'rt=$request_time uct=$upstream_connect_time '
                'uht=$upstream_header_time urt=$upstream_response_time';

access_log /var/log/nginx/access.log main;

# 按 location 关闭日志
location /health {
  access_log off;
  return 200;
}
$request_time vs $upstream_response_time——前者是 Nginx 从收到请求到响应的总时间,后者是后端的处理时间。差值太大说明 Nginx 自己处理(如静态文件)或网络传输花了时间。

02. error_log——记录错误与调试

error_log 记录 Nginx 遇到的错误、警告和调试信息。错误日志级别从低到高:debug、info、notice、warn、error、crit、alert、emerg。 生产环境通常设 warn 或 error 级别。设 debug 级别日志量爆炸且有性能影响,只用于排查具体问题(需要编译 Nginx 时加上 --with-debug 支持)。 error_log 可以配置到文件、syslog、或者 stderr(容器里常用,日志收集系统统一收)。 常见的 error_log 里的问题: upstream timed out——后端响应超时。 connect() failed——连不上后端。 SSL 相关错误——证书配置问题。 permission denied——文件权限问题。
nginx
# 错误日志配置
error_log /var/log/nginx/error.log warn;

# 输出到 syslog
error_log syslog:server=localhost:514 warn;

# 调试模式(仅临时用)
error_log /var/log/nginx/debug.log debug;
# 需要 Nginx 编译时有 --with-debug

# 按条件记错误日志
map $status $loggable {
  ~^[23]  0;
  default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;
nginx -t 只能检查语法错误。运行时的问题(如连不上后端)只能从 error_log 里看。

03. 日志轮转——别让磁盘撑满

Nginx 自己不管日志轮转,日志文件会一直变大。需要用 logrotate 或操作系统的工具定期切割压缩旧日志。 logrotate 是 Linux 的标准日志管理工具——它定期把旧的日志文件重命名、压缩,并通知 Nginx 打开新日志文件(通过 USR1 信号)。 典型的配置:每天轮转、保留 30 天、压缩旧文件、延迟压缩(避免当前正在写的文件被压缩)。 注意:logrotate 执行后需要 kill -USR1 给 Nginx 发信号让它的日志指向新文件。或者用 copytruncate 模式直接截断(但可能丢几行日志)。
bash
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
  daily                       # 每天轮转一次
  missingok                   # 日志文件不存在不报错
  rotate 30                   # 保留 30 份
  compress                    # 压缩旧日志
  delaycompress               # 延迟压缩(留一份不压缩方便查看)
  notifempty                  # 空文件不轮转
  create 640 nginx adm        # 创建新文件的权限
  sharedscripts
  postrotate
    if [ -f /var/run/nginx.pid ]; then
      kill -USR1 `cat /var/run/nginx.pid`
    fi
  endscript
}

04. 条件日志与动态日志

Nginx 可以用 if 条件控制是否记录日志——健康检查、静态资源这些不需要记录的内容可以关掉日志,减少磁盘 IO 和日志量。 使用 map 指令定义一个变量,根据条件设置为 0(不记)或 1(记)。access_log 用 if= 条件引用这个变量。 还有 buffered 日志模式——Nginx 把日志先写缓冲区再批量刷盘,减少磁盘 IO 次数。buffer 和 flush 参数控制缓冲区大小和刷盘频率。 gzip 日志——日志量大时可以设置 access_log 输出通过管道传给 gzip 程序实时压缩。
nginx
# 条件日志——健康检查和静态文件不记
map $uri $loggable {
  /health 0;
  ~* \.(css|js|png|jpg|gif)$ 0;
  default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;

# 缓冲日志
access_log /var/log/nginx/access.log combined buffer=64k flush=5s;

# 压缩日志(pipe 到 gzip)
access_log /var/log/nginx/access.log.gz combined gzip buffer=64k flush=5s;
缓冲日志的 flush 参数——日志在缓冲区里最多待多少秒就必须刷盘。5s 意味着最多丢最近 5 秒的日志(Nginx 挂了的话)。

05. JSON 日志与 ELK 集成

传统文本日志难以程序化分析。现在流行用 JSON 格式输出日志,直接喂给 ELK(Elasticsearch + Logstash + Kibana)或 Loki 做聚合分析。 JSON 日志定制——用 log_format 定义 JSON 格式(注意要 escape 特殊字符)。关键字段:时间戳、客户端 IP、请求 URI、状态码、响应时间、User-Agent。 配合 Filebeat 或 Fluentd 把 JSON 日志采集到 Elasticsearch。 注意:JSON 日志里别用 $http_ 开头的变量(如 Cookie)全部输出——可能泄露敏感信息。只记录需要分析的必要字段。
nginx
# JSON 格式日志
log_format json_combined escape=json '{'
  '"timestamp":"$time_iso8601",'
  '"remote_addr":"$remote_addr",'
  '"real_ip":"$http_x_forwarded_for",'
  '"method":"$request_method",'
  '"uri":"$request_uri",'
  '"status":$status,'
  '"body_bytes":$body_bytes_sent,'
  '"request_time":$request_time,'
  '"upstream_time":$upstream_response_time,'
  '"user_agent":"$http_user_agent"'
'}';

access_log /var/log/nginx/access.json json_combined;
escape=json 是 Nginx 1.11.8 加入的参数,自动把变量里的引号反斜杠等转义成合法 JSON。不用自己手动处理了。

知识测验

1/5正确 0

access_log 和 error_log 分别记什么?