Linux 服务器日志不再撑爆磁盘:logrotate + Python logging 日志轮转实战

举报
yd_276596855 发表于 2026/11/09 11:21:35 2026/11/09
【摘要】 一、问题从哪里来很多人把 Python Web 应用部署到云服务器后,前几周一切正常,某天突然发现服务挂了,一查才知道磁盘被日志写满了。应用日志、访问日志、错误日志每天都在增长,没有人清理,几个月下来就是几十 GB。这篇文章用一台普通的 Linux 云服务器,演示两种互补的做法:在应用内部用 Python 标准库 logging 自带的轮转处理器控制日志大小;在系统层用 logrotate ...

一、问题从哪里来

很多人把 Python Web 应用部署到云服务器后,前几周一切正常,某天突然发现服务挂了,一查才知道磁盘被日志写满了。应用日志、访问日志、错误日志每天都在增长,没有人清理,几个月下来就是几十 GB。

这篇文章用一台普通的 Linux 云服务器,演示两种互补的做法:

  1. 在应用内部用 Python 标准库 logging 自带的轮转处理器控制日志大小;
  2. 在系统层用 logrotate 统一管理所有服务的日志,按天切分、压缩、自动删除旧文件。

二、方案一:Python logging 自带轮转

Python 标准库里有两个现成的处理器:

  • RotatingFileHandler:按文件大小轮转;
  • TimedRotatingFileHandler:按时间轮转(每天、每小时等)。

按天轮转、保留 14 天的写法如下(入口文件 app 中):

import os
import logging
from logging.handlers import TimedRotatingFileHandler

handler = TimedRotatingFileHandler(
    filename=os.environ.get("LOG_FILE", "/var/log/myapp/app_log"),
    when="midnight",
    interval=1,
    backupCount=14,
    encoding="utf-8",
)
handler.setFormatter(logging.Formatter(
    "%(asctime)s %(levelname)s %(name)s %(message)s"
))

logger = logging.getLogger("myapp")
logger.setLevel(logging.INFO)
logger.addHandler(handler)

logger.info("service started")

要点:

  • when 设为 midnight 表示每天零点切分;
  • backupCount 决定保留多少份历史文件,超过的自动删除;
  • 一定要指定 encoding,否则中文日志在某些环境下会乱码。

这个方案的局限:如果用 Gunicorn 起了多个 worker 进程,多个进程同时写同一个文件并各自轮转,会出现日志丢失或文件互相覆盖。多进程场景更推荐把日志交给系统层统一处理。

三、方案二:用 logrotate 统一管理

大部分 Linux 发行版自带 logrotate,并由系统定时任务每天执行一次。我们只需要在其配置目录下为应用新建一份配置。

  1. 在 /etc 下的 logrotate 配置目录里新建一个名为 myapp 的配置文件,内容如下:
/var/log/myapp/* {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    dateext
    copytruncate
    create 0640 www-data www-data
}

逐行解释:

  • daily:每天轮转一次,也可以用 weekly、monthly;
  • rotate 14:保留 14 份,更旧的直接删除;
  • missingok:日志文件不存在时不报错;
  • notifempty:文件为空时不轮转;
  • compress / delaycompress:旧日志用 gzip 压缩,但最近一份暂不压缩,方便排查;
  • dateext:历史文件名带日期后缀,比数字后缀更好找;
  • copytruncate:先复制再清空原文件,应用不需要重新打开文件句柄;
  • create:指定新文件的权限和属主。
  1. 先做一次“演练”,确认配置没写错:
sudo logrotate -d 配置文件路径

-d 是调试模式,只打印将要执行的动作,不会真的改文件。

  1. 强制执行一次,看效果:
sudo logrotate -f 配置文件路径
ls -lh /var/log/myapp/

能看到多出一份带日期后缀的文件,原日志被清空,说明配置生效。

四、copytruncate 和 postrotate 怎么选

copytruncate 简单省事,但在“复制”和“清空”之间的极短时间里写入的日志可能丢失。对日志完整性要求高的服务,可以改用让应用重新打开日志文件的方式:

/var/log/myapp/* {
    daily
    rotate 14
    compress
    delaycompress
    dateext
    sharedscripts
    postrotate
        systemctl kill -s USR1 myapp
    endscript
}

Gunicorn 收到 USR1 信号后会重新打开日志文件,不会中断服务。Nginx 也有类似机制,它自带的 logrotate 配置就是这么做的。

五、顺手检查一下 systemd 日志

如果服务是用 systemd 托管、日志走 journald 的,还要限制 journal 的总大小,否则它同样会慢慢吃掉磁盘。

查看当前占用:

journalctl --disk-usage

在 journald 的配置文件(/etc/systemd 目录下的 journald 配置)中设置上限,例如:

SystemMaxUse=500M
MaxRetentionSec=2week

然后重启 journald:

sudo systemctl restart systemd-journald

也可以一次性清理:

sudo journalctl --vacuum-size=500M

六、最后加一道保险:磁盘告警

日志轮转之外,建议再加一个简单的磁盘检查脚本,用系统定时任务每小时跑一次,使用率超过 85% 就写一条告警日志或发通知:

#!/bin/bash
USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -gt 85 ]; then
    logger -t disk-check "root disk usage ${USAGE}%"
fi

在云服务器上,也可以直接使用云监控服务配置磁盘使用率告警,更省心。

七、总结

  • 单进程小应用:Python logging 的 TimedRotatingFileHandler 就够用;
  • 多进程或多服务:交给 logrotate 统一管理,配合 postrotate 信号或 copytruncate;
  • 别忘了 journald 也要设上限;
  • 再加一道磁盘告警,问题出现前就能发现。

把这几步做完,服务器就不会再因为日志撑爆磁盘而半夜宕机了。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。