判断日志是否超期应基于最后修改时间早于当前时间减30天,用os.path.getmtime()与time.time()对比;Windows下mtime可能为创建时间,推荐优先解析文件名中的日期;清理时需限定后缀、避免子目录、加dry-run和权限检查,并单独处理符号链接。

用 os.path.getmtime() 判断日志文件是否超期
关键不是“30天前”,而是“最后修改时间早于当前时间减去30天”。os.path.getmtime() 返回的是 Unix 时间戳(秒级),必须和 time.time() 对齐计算,不能直接用字符串日期比较。注意:Windows 下该函数返回的是创建时间而非修改时间(NTFS 卷上可能不一致),如果日志是写完即关闭的,一般仍可用;若需严格按写入完成时间清理,建议统一用日志文件名中的时间戳(如 app.log.2024-05-01)解析。
遍历目录时避开子目录或只清理指定后缀
默认用 os.listdir() 会拿到所有条目,包括子目录、临时文件、隐藏文件。实际清理日志时,通常只处理 .log、.out、.err 等后缀,且不递归进子目录(除非明确需要)。推荐用 pathlib.Path.iterdir() 配合 suffix 判断,更安全:
from pathlib import Path
log_dir = Path("/var/log/myapp")
for f in log_dir.iterdir():
if f.is_file() and f.suffix in {".log", ".out", ".err"}:
if time.time() - f.stat().st_mtime > 30 * 86400:
f.unlink()
删除前加 dry-run 模式和权限检查
直接 f.unlink() 有风险,尤其在 root 或服务目录下运行时。务必先确认进程有写权限,否则会抛 PermissionError;也别跳过只读文件(如 chmod -w app.log 后的文件),unlink() 默认无法删除。建议步骤:
- 先用
f.stat().st_mode & 0o200检查用户是否有写权限 - 用布尔开关控制是否真正删除:
dry_run=True时只打印路径和预估时间差 - 捕获
OSError而非宽泛的Exception,避免掩盖逻辑错误 - 对符号链接用
f.is_symlink()单独处理,避免误删目标文件
用 glob 匹配带日期的归档日志(如 app.log.2024-04-01)
很多日志轮转工具(如 logrotate)生成的归档文件名含日期,这时靠 getmtime 反而不准——文件可能被 cp/mv 过,mtime 已变。更可靠的方式是解析文件名:
立即学习“Python免费学习笔记(深入)”;
from datetime import datetime, timedelta
cutoff = datetime.now() - timedelta(days=30)
for f in log_dir.glob("*.log.*"):
try:
date_part = f.stem.split(".")[-1] # "app.log.2024-04-01" → "2024-04-01"
file_date = datetime.strptime(date_part, "%Y-%m-%d")
if file_date < cutoff:
f.unlink()
except ValueError:
continue # 名字不含标准日期格式,跳过
这种模式对命名不规范的文件容错弱,但对受控环境(如自己写的日志脚本)最稳定。注意 glob 不会匹配隐藏文件(以 . 开头),也不进子目录,符合多数清理场景。
实际部署时,cron 调用脚本比用 threading.Timer 更可靠;而文件名解析和 mtime 判定应根据日志生成方式二选一,混用反而增加误删概率。


















