1. Nginx 日志的类型
  2. 日志格式的定义
  3. 如何配置日志
  4. 日志轮转与切割(防止日志文件过大)
  5. 日志分析工具与实战
  6. 日志的最佳实践

Nginx 日志的类型

Nginx 主要有两种类型的日志:

nginx 网站 日志
(图片来源网络,侵删)

a) 访问日志

这是最常用、最重要的日志,它记录了每一个客户端(如浏览器、爬虫)与 Nginx 服务器交互的详细信息。

  • 作用
    • 分析网站流量:访问量、独立访客数、页面浏览量。
    • 了解用户行为:用户从哪里来(Referer)、访问了哪些页面(URI)、使用什么浏览器和操作系统(User-Agent)。
    • 性能分析:哪些页面响应慢(响应时间 request_time)。
    • SEO 优化:分析搜索引擎的抓取情况。
    • 安全审计:发现异常的访问模式,如暴力破解、爬虫扫描。

b) 错误日志

当 Nginx 在处理请求时遇到问题,或者自身启动、运行出错时,它会记录错误日志。

  • 作用
    • 服务器排错:是解决 Nginx 配置问题、应用问题(如后端服务不可用)的“第一手”资料。
    • 监控服务器健康状态:可以设置监控工具,当错误日志出现特定错误(如 502 Bad Gateway)时发出警报。
    • 调试:包含详细的错误级别和上下文信息,帮助定位问题根源。

日志格式的定义

Nginx 允许你自定义日志的格式,以便记录你关心的任何信息,默认情况下,Nginx 已经定义了两种格式:

  • combined:这是最常用的访问日志格式,包含了丰富的信息。
  • main:在某些版本中是默认格式,信息比 combined 少一些。

你可以在 Nginx 的配置文件(通常是 nginx.confconf.d/ 目录下的 .conf 文件)中使用 log_format 指令来定义自己的格式。

nginx 网站 日志
(图片来源网络,侵删)

log_format 指令语法

log_format name [escape=default|json] string ...;
  • name:给这个格式定义一个名字,my_custom_format
  • escape:指定如何转义特殊字符,json 是个好选择,方便后续程序解析。
  • string的模板,可以包含变量和文本。

常用变量列表

变量 含义
$remote_addr 客户端 IP 地址
$http_x_forwarded_for 当你使用了反向代理(如 Nginx 代理 Tomcat)时,记录客户端的真实 IP。
$time_local 服务器本地时间(标准格式)
$request 完整的原始请求行(如 GET /index.html HTTP/1.1
$status HTTP 响应状态码(如 200, 404, 500)
$body_bytes_sent 发送给客户端的 body 内容大小(字节)
$http_referer 引用页面的地址(从哪里点进来的)
$http_user_agent 客户端的浏览器信息(User-Agent 字符串)
$request_time 整个请求处理完毕所花费的时间(秒,毫秒级精度)
$upstream_response_time Nginx 与后端服务器建立连接到接收完响应头的时间(不包括响应体传输时间)
$upstream_addr 后端服务器的地址

默认 combined 格式示例

Nginx 自带的 combined 格式定义如下:

log_format combined '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

这个格式产生的日志行就像这样: 168.1.100 - - [10/Oct/2025:13:55:36 +0800] "GET /api/users HTTP/1.1" 200 512 "https://www.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" "-"


如何配置日志

配置日志主要在 server 块或 http 块中进行。

a) 配置访问日志

server 块中,使用 access_log 指令指定日志文件的路径和使用的格式。

nginx 网站 日志
(图片来源网络,侵删)

示例 1:基本配置

server {
    listen 80;
    server_name www.example.com;
    # 访问日志记录到 /var/log/nginx/www.example.com.access.log,
    # 使用默认的 combined 格式
    access_log /var/log/nginx/www.example.com.access.log;
    location / {
        root /var/www/html;
        index index.html;
    }
}

示例 2:使用自定义格式

# 在 http 块中定义一个新的日志格式
http {
    # ... 其他 http 配置 ...
    log_format json escape=json '{'
        '"timestamp": "$time_iso8601",'
        '"remote_addr": "$remote_addr",'
        '"request": "$request",'
        '"status": $status,'
        '"body_bytes_sent": $body_bytes_sent,'
        '"request_time": $request_time,'
        '"upstream_response_time": "$upstream_response_time"'
    '}';
    server {
        listen 80;
        server_name api.example.com;
        # 使用我们刚刚定义的 json 格式
        access_log /var/log/nginx/api.example.com.access.log json;
        location / {
            # 假设这是一个反向代理
            proxy_pass http://backend_server;
        }
    }
}

b) 配置错误日志

错误日志通常在 main(主)配置级别或 http 级别定义,这样所有虚拟主机都会共享同一个错误日志,你也可以在 server 块中为特定网站单独配置。

使用 error_log 指令。

语法error_log file [level];

  • file:日志文件路径。
  • level:日志级别,级别从低到高为:debug, info, notice, warn, error, crit, alert, emerg,记录的级别是 及以上 的,设置为 error,则会记录 error, crit, alert, emerg 级别的日志。

示例

# 在 http 块或主配置文件中设置
error_log /var/log/nginx/error.log warn;
# 在某个 server 块中覆盖
server {
    # ...
    error_log /var/log/nginx/www.example.com.error.log; # 不指定级别,默认是 error
    # ...
}

日志轮转与切割

Nginx 的日志文件会不断增长,如果不加以处理,很快就会占满整个硬盘,必须配置日志轮转。

Linux 系统通常使用 logrotate 工具来自动完成这项工作。

/etc/logrotate.d/nginx 文件示例

这个文件通常由 Nginx 安装包自动创建或提供。

/var/log/nginx/*.log {
    daily               # 每天轮转一次
    missingok           # 如果日志文件不存在,不报错
    rotate 7            # 保留7个旧日志文件
    compress            # 轮转后进行压缩,节省空间
    delaycompress       # 延迟一天再压缩,这样最新的旧日志可以方便排查问题
    notifempty          # 如果日志为空,则不轮转
    create 0644 www-data www-data # 创建新日志文件时的权限和所有者
    sharedscripts       # 脚本只在所有日志轮转后执行一次
    postrotate
        # Nginx 正在运行,则需要向其发送 USR1 信号,
        # 通知它重新打开日志文件,继续写入新的日志文件
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

logrotate 通常由 cron 每天自动执行,它会检查配置文件,对满足条件的日志文件进行轮转。


日志分析工具与实战

拿到日志文件后,如何分析呢?

a) 命令行工具(Linux/Unix)

  • 查看日志尾部(实时监控)

    tail -f /var/log/nginx/access.log

    这是最常用的实时查看日志的方法,-f 表示跟随文件末尾的变化。

  • 统计访问量最高的 URL

    # 统计访问次数最多的前10个URL
    awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10
    • awk '{print $7}':提取日志中的第7个字段(通常是请求的 URI)。
    • sort:排序。
    • uniq -c:合并连续的相同行,并计数。
    • sort -nr:按数字(-n)逆序(-r)排序。
    • head -n 10:显示前10行。
  • 统计访问量最高的 IP

    awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10
  • 统计 HTTP 状态码

    awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr

    这可以帮你快速定位 404、500 等错误。

  • 使用 goaccess 进行可视化分析goaccess 是一个非常强大的、实时的、交互式的日志分析器,它能生成漂亮的 HTML 报告。

    安装

    # Ubuntu/Debian
    sudo apt-get install goaccess
    # CentOS/RHEL
    sudo yum install goaccess

    使用

    # 分析日志并生成 HTML 报告
    goaccess /var/log/nginx/access.log -o /var/www/html/report.html --real-time-html

    然后你就可以在浏览器中访问 http://your_server_ip/report.html 查看实时更新的分析报告。

b) ELK/EFK 栈(企业级方案)

对于大型网站,通常会将日志发送到集中的日志分析平台,如 ELK Stack (Elasticsearch, Logstash, Kibana)EFK Stack (Elasticsearch, Fluentd, Kibana)

  • 流程:Nginx 日志 -> (Filebeat/Fluentd) -> Logstash/Fluentd -> Elasticsearch -> Kibana
  • 优点
    • 集中管理:所有服务器的日志都在一个地方。
    • 强大的搜索和聚合:可以基于任意字段进行复杂查询和聚合分析。
    • 可视化:通过 Kibana 创建各种图表和仪表盘,直观展示网站数据。
    • 告警:可以设置阈值,当满足条件时(如 5xx 错误超过 100 次/分钟)发送邮件或短信告警。

日志的最佳实践

  1. 为每个虚拟主机使用独立的访问日志:便于隔离和分析特定网站的数据。
  2. 为后端 API 使用 JSON 格式日志:结构化日志更易于机器解析和分析。
  3. 记录关键性能指标:如 $request_time$upstream_response_time,对性能优化至关重要。
  4. 配置并测试日志轮转:这是服务器运维的基石,避免磁盘被撑爆。
  5. 保护日志文件安全:日志文件可能包含敏感信息(如用户 IP、路径),确保日志文件权限设置正确(如 640),并限制只有授权用户才能访问。
  6. 建立监控和告警:监控错误日志的增长率和特定错误码的出现频率,及时发现并解决问题。
  7. 定期归档和分析:不要让日志文件堆积如山,定期将旧日志归档到对象存储(如 S3)中,并进行分析,为业务决策提供数据支持。