Nginx配置访问日志,日志切割和分析

前言

Nginx 默认就会记录访问日志,放在 /var/log/nginx/ 目录下。但日志每天都在涨,时间长了占满磁盘,还不好查。本文就讲一下 Nginx 日志配置、切割和分析方法。

默认日志位置

Nginx 默认日志文件:

/var/log/nginx/
├── access.log    # 访问日志
└── error.log     # 错误日志

日志格式

Nginx 默认的日志格式叫 combined,记录这些信息:

  • 客户端 IP
  • 访问时间
  • 请求方法和路径
  • 状态码
  • 响应大小
  • Referer
  • User-Agent

自定义日志格式

在 nginx.conf 的 http 块里可以自定义日志格式:

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

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

常用变量

变量 说明
$remote_addr 客户端 IP
$time_local 本地时间
$request 请求行
$status 状态码
$body_bytes_sent 响应大小
$http_referer 来源页面
$http_user_agent 浏览器信息
$request_time 请求耗时

按站点分日志

不同站点的日志分开存,方便排查问题:

server {
    listen 80;
    server_name www.example.com;

    access_log  /var/log/nginx/example.com.access.log;
    error_log   /var/log/nginx/example.com.error.log;
}

日志切割

用 logrotate 切割

CentOS7 装完 Nginx 就自动配了 logrotate,不用管。配置文件在:

/etc/logrotate.d/nginx

内容大概是:

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    notifempty
    create 0640 nginx adm
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

意思是:

  • 每天切割一次
  • 保留 14 天
  • 压缩旧日志
  • 空日志不切割

手动测试切割

logrotate -f /etc/logrotate.d/nginx

日志分析常用命令

查看访问量前 10 的 IP

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

查看访问量前 10 的页面

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

查看状态码统计

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

查看爬虫访问

grep 'Googlebot' /var/log/nginx/access.log

查看某个 IP 的访问

grep '192.168.1.1' /var/log/nginx/access.log

常见坑

坑1:日志越来越大占满磁盘

日志不切割,时间长了把磁盘占满。

解决: 确认 logrotate 在运行:

cat /var/lib/logrotate.status

或者手动执行一次:

logrotate -f /etc/logrotate.d/nginx

坑2:日志里 IP 不对

日志里全是 127.0.0.1,不是真实用户 IP。

原因: Nginx 前面还有一层代理(比如 CDN),或者配了反向代理。

解决: 用 $http_x_forwarded_for 代替 $remote_addr:

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

坑3:日志级别太高

错误日志里全是 notice,没用还占空间。

解决: 把错误日志级别调高一点:

error_log /var/log/nginx/error.log warn;

可选级别:debug、info、notice、warn、error、crit。

总结

Nginx 日志的常用操作:

操作 命令
看访问日志 tail -f /var/log/nginx/access.log
看错误日志 tail -f /var/log/nginx/error.log
统计 IP awk '{print $1}' access.log \| sort \| uniq -c
统计页面 awk '{print $7}' access.log \| sort \| uniq -c
手动切割 logrotate -f /etc/logrotate.d/nginx

日志是排查问题的第一手资料,学会看日志比什么都重要。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-5 07:58 

Linux日志过大占用磁盘,logrotate日志切割配置

前言

服务器跑了几个月,突然磁盘满了,一查发现是日志文件占了几十G。Nginx的access.log、MySQL的慢查询日志、系统日志……这些日志文件只会越来越大,不会自己变小。手动删了吧,又怕删出问题;不删吧,磁盘迟早满。Linux 自带了 logrotate 工具,专门用来自动切割和清理日志,配置一次以后就不用管了。本文就详细讲一下怎么用 logrotate 管理日志。

什么是 logrotate

logrotate 是 Linux 系统自带的日志管理工具,可以自动完成:

  • 切割日志:把大日志文件按天/按大小切成多个小文件
  • 压缩日志:旧的日志自动 gzip 压缩
  • 删除日志:保留指定天数后自动删除
  • 通知服务:切割完后通知 Nginx/MySQL 等服务重新打开日志文件

系统默认每天运行一次 logrotate,你只需要写好配置文件就行。

logrotate 配置文件结构

全局配置

vi /etc/logrotate.conf

这是全局配置文件,一般不用改。里面定义了默认的行为:

weekly                  # 默认每周切割一次
rotate 4                # 保留4个日志文件
create                  # 切割后创建新的空日志文件
dateext                 # 用日期作为扩展名
include /etc/logrotate.d   # 包含这个目录下的所有配置

单个服务的配置

每个服务的日志配置放在 /etc/logrotate.d/ 目录下:

ls /etc/logrotate.d/

比如 nginx、mysql、syslog 都有各自的配置文件。

实战:配置 Nginx 日志切割

我们以 Nginx 为例,写一个完整的 logrotate 配置。

1. 创建配置文件

vi /etc/logrotate.d/nginx

2. 写入配置

/var/log/nginx/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 nginx nginx
    postrotate
        /usr/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endpostrotate
}

3. 参数说明

参数 作用
/var/log/nginx/*.log 要切割的日志文件路径
daily 每天切割一次
rotate 30 保留30个日志文件
compress 旧日志用gzip压缩
delaycompress 延迟压缩,新切割的当天不压缩
missingok 日志文件不存在不报错
notifempty 空文件不切割
create 644 nginx nginx 创建新文件,权限644,属主nginx
postrotate...endpostrotate 切割后执行的命令,通知Nginx重新打开日志文件

常用切割策略

按天切割,保留30天

/var/log/nginx/*.log {
    daily
    rotate 30
    compress
    missingok
    notifempty
    create 644 nginx nginx
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endpostrotate
}

按大小切割,超过100M就切

/var/log/nginx/access.log {
    size 100M
    rotate 10
    compress
    missingok
    notifempty
    create 644 nginx nginx
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endpostrotate
}

同时按天+按大小

/var/log/nginx/*.log {
    daily
    size 100M
    rotate 30
    compress
    missingok
    notifempty
    create 644 nginx nginx
    postrotate
        /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
    endpostrotate
}

意思是每天检查一次,如果日志超过100M就切割。

手动测试 logrotate

配置完之后,可以用 debug 模式测试一下,不会真正执行:

logrotate -d /etc/logrotate.d/nginx

参数说明:

  • -d:debug模式,只显示会做什么,不真正执行

如果没问题,手动执行一次:

logrotate -f /etc/logrotate.d/nginx
  • -f:强制切割,不管到没到时间

常见坑

坑1:切割了但服务还在写旧文件

很多人配置完 logrotate,发现日志切完了,但磁盘空间没释放。这是因为 Nginx 还在往旧的日志文件里写(虽然名字改了,但文件句柄还在)。

解决: 一定要配置 postrotate 脚本,通知服务重新打开日志文件。对于 Nginx,就是发送 USR1 信号:

postrotate
    /bin/kill -USR1 `cat /run/nginx.pid`
endpostrotate

坑2:压缩延迟没开,旧日志还占着空间

如果不加 delaycompress,切割完立刻就压缩,但服务可能还在写旧文件,导致压缩失败或者压缩不完整。

解决: 加上 delaycompress,让新切割的日志第二天再压缩。

坑3:日志文件权限不对

切割完创建的新日志文件,如果属主不对,Nginx 就写不进去。

解决: 用 create 644 nginx nginx 指定新文件的属主和权限。

坑4:logrotate 不执行

配置写完了,但日志从来没切割过。检查一下:

# 看logrotate的cron任务有没有
cat /etc/cron.daily/logrotate

# 手动执行一次看有没有报错
logrotate -d /etc/logrotate.d/nginx

总结

logrotate 配置的核心步骤:

  1. 在 /etc/logrotate.d/ 下创建配置文件
  2. 指定日志路径、切割频率、保留数量
  3. 加上 postrotate 通知服务重新打开日志
  4. 用 logrotate -d 测试配置
  5. 系统每天自动执行,不用管了

日志切割是服务器运维的基本功,配好了以后磁盘永远不会被日志撑满。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-5 07:33