在 open() 中处理 logrotate

Handling logrotate in open()

我正在使用以下函数逐行跟踪和处理日志文件:

def tail(f):
    f.seek(0,2)
    while True:
        line = f.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

with open("/var/log/some.log") as f:
    for line in tail(f):
    ...

logrotate 旋转文件时,该函数卡在最后一行。我想 logrotate 会移动文件并创建一个新文件,让程序仍在等待旧文件的行。

处理此问题的好方法是什么 - 发生旋转时重新打开文件?

通常的标准方法是告诉 logrotate 将 HUP 信号发送到处理日志的 service/program。

在 logrotate 配置中,这是通过 postrotate 脚本完成的:

   postrotate
       /usr/bin/killall -HUP your_process
   endscript

然后在您的 python 程序中,您必须处理信号 HUP。您在 python's signal doc 中有一个示例。您需要处理 signal.SIGHUP


另一种不太标准的方法是将 inode 编号与(可能)新的 inode 编号进行比较。如果这些数字不同,那么您就知道该文件已更改,您需要重新打开它。

我试过类似的方法,它似乎有效:

import os
import time

logname = "logfile"
logfile = open(logname, "r")

def tail(f):
    f.seek(0,2)
    inode = os.fstat(f.fileno()).st_ino

    while True:
        line = f.readline()
        if not line:
            time.sleep(0.1)
            if os.stat(logname).st_ino != inode:
                f.close()
                f = open(logname, 'r')
                inode = os.fstat(f.fileno()).st_ino
            continue
        yield line

for line in tail(logfile):
    ...