You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell脚本调用Python脚本超2小时后日志无法写入文件问题

长耗时Python脚本Shell调用下日志写入异常排查与修复

核心现象

直接在Linux终端执行Python脚本时,日志可正常完整写入目标文件;通过Shell脚本调用执行时,程序持续运行2~3小时及更长时间后,日志无法继续写入文件。


常见根因与对应修复方案

1. 流缓冲模式差异导致日志滞留在内存

直接在终端执行Python时,进程检测到stdout/stderr绑定到TTY设备,默认采用行缓冲模式,每输出一行日志就会立即刷入磁盘,因此日志写入正常。
当通过Shell脚本调用时,Python进程的stdout/stderr不再关联TTY,会自动切换为*全缓冲(块缓冲)*模式,缓冲区默认大小为4KB~8KB,仅当缓冲区写满、进程正常退出、手动执行flush操作时,才会把缓冲区内容写入磁盘。长时运行场景下如果日志输出频率不稳定,很容易出现日志长时间滞留在内存、看起来没有写入文件的现象,极端情况下进程异常退出时缓冲区内容会直接丢失。
修复方式:

  • 调用Python时添加-u参数,强制关闭stdout/stderr的全缓冲:
# Shell脚本中修改Python调用命令为如下形式
python3 -u your_target_script.py >> /var/log/your_app.log 2>&1
  • 如果使用Python内置logging模块写日志,显式配置写入后立即刷盘:
import logging

file_handler = logging.FileHandler("/var/log/your_app.log")
# 配置日志格式
file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
# 每次输出日志后强制刷入磁盘
original_emit = file_handler.emit
def emit_with_flush(record):
    original_emit(record)
    file_handler.stream.flush()
file_handler.emit = emit_with_flush

logger = logging.getLogger(__name__)
logger.addHandler(file_handler)
logger.setLevel(logging.INFO)
  • 如果直接用print输出日志,给所有print调用添加flush=True参数:print("your log content", flush=True)

2. 日志切割后文件句柄未更新

如果日志目录配置了logrotate按时间/大小切割,长时运行2~3小时刚好触发切割规则时,logrotate会默认将旧日志重命名为your_app.log.1,再创建新的your_app.log文件。此时如果Python进程、Shell重定向逻辑仍持有旧文件的inode句柄,后续日志会持续写入已经被重命名的旧文件,你查看新的日志文件时就会发现没有新内容写入,误以为日志写入中断。
修复方式:

  • 修改logrotate配置,对该日志文件添加copytruncate参数,切割时复制原文件内容后直接清空原文件,不需要进程重新打开文件句柄
  • 优先使用Python logging模块自带的RotatingFileHandler/TimedRotatingFileHandler实现日志切割,不要依赖系统层logrotate切割进程已打开的日志文件
  • 如果必须使用系统logrotate,给Python进程增加日志句柄重载逻辑,切割完成后给进程发送SIGUSR1信号触发重新打开日志文件

3. 父Shell进程退出导致文件描述符失效

如果Shell脚本中只是简单把Python进程放到后台执行(比如直接写python3 your_script.py &),没有做进程托管,当Shell脚本执行完毕退出后,父进程打开的文件描述符会被系统回收,此时Python进程持有的日志文件句柄失效,后续写入操作会触发Bad file descriptor错误,由于这类错误默认不会输出到可见的日志中,外在表现就是日志停止写入。
修复方式:

  • 长时运行的Python进程不要通过Shell嵌套调用启动,优先使用systemd、supervisor这类专业进程管理器托管,在服务配置中固定日志重定向规则、进程重启策略
  • 如果临时需要通过Shell启动,使用nohup脱离终端和父进程关联,示例:nohup python3 -u your_script.py >> /var/log/your_app.log 2>&1 &

4. 磁盘资源耗尽

长时运行场景下日志持续写入,如果没有配置切割清理策略,2~3小时的日志量可能刚好写满日志所在分区的磁盘空间,或者耗尽分区inode,此时所有写入文件的操作都会失败。直接在终端执行时往往运行时间较短,没有触发资源耗尽阈值,因此不会暴露问题。
排查命令:

# 查看磁盘空间使用率
df -h
# 查看inode使用率
df -i

修复方式:清理分区内冗余文件,配置日志自动切割、过期清理策略,避免磁盘资源被写满。


内容的提问来源于stack exchange,提问作者Priyanka Chaudhari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:33:43