Python 计划日志轮换

3

编辑:

看起来其他人也遇到了与TimedRotatingFileHandler相关的类似问题。

Python TimedRotatingFileHandler在午夜不会旋转,直到有新内容写入日志文件。如何解决?

为什么我的TimedRotatingFileHandler在午夜不会旋转?

显然,只有在日志中发生某些活动时,才会进行日志轮换。是否有一种方法可以使用内置处理程序实现我想要的定期旋转功能,而无需创建自定义旋转器?


原始帖子:

我正在使用Python的logging模块的TimedRotatingFileHandler来定期轮换我的日志。

我已在logging.conf中为我的应用程序的记录器和处理程序指定了配置,如下所示:

[logger_worker]
level=DEBUG
propogate=0
qualname=worker
handlers=workerHandler

[handler_workerHandler]
class=handlers.TimedRotatingFileHandler
level=DEBUG
formatter=standardFormatter
args=("/var/log/app/worker.log","M",1,30,None,False,False)
  • 注意:出于测试目的,我已将处理程序配置为每分钟轮换日志,但理想情况下,日志应在午夜每天轮换一次。

在我的应用程序中,我是这样创建记录器的:

logging.config.fileConfig("logging.conf")
log = logging.getLogger("worker")

log.debug('Hello world')

它并没有按照我的预期工作:

  1. 它没有旋转所有的日志
  2. 它没有按照配置的每分钟旋转

观察日志目录的ls -l输出:

-rw-r--r-- 1 root root       0 Apr 19 18:22 dpv.log
-rw-r----- 1 root root    5092 Apr 20 11:47 emperor.log
-rw-r--r-- 1 root root   88939 Apr 20 11:47 uwsgi.log
-rw-r--r-- 1 root root     494 Apr 20 11:46 worker.log
-rw-r--r-- 1 root root   45906 Apr 20 02:08 worker.log.2016-04-20_02-08
-rw-r--r-- 1 root root     494 Apr 20 11:34 worker.log.2016-04-20_11-34
-rw-r--r-- 1 root root     494 Apr 20 11:36 worker.log.2016-04-20_11-36
-rw-r--r-- 1 root root     494 Apr 20 11:44 worker.log.2016-04-20_11-44

我做错了什么?即使没有任何内容被写入日志,也可以按计划轮换日志吗?

你有多少次调用了 log.debug('Hello world') - qvpham
@julivico,该应用程序在许多地方都充满了日志。对于每个请求,该应用程序会在各个位置记录大约100多行的日志。因此,我想这取决于在给定时间段内有多少请求。传入的请求可能是每秒50个或每小时1个,这完全是可变的并由用户决定。但即使没有活动,我仍然希望日志能够轮换。是否可能? - tamjd1
如果没有活动,日志记录也会停止。因此,日志不会被轮换。我认为,您每天进行轮换就不会遇到这个问题。或者您可以在Linux系统上使用logrotate - qvpham
我会考虑使用logrotate作为替代方案... 感谢@julivico。 - tamjd1
2个回答

1

我曾经遇到过同样的问题,并想出了一种不同的方法:

from datetime import datetime
import os

def rotate_log_if_new_day(self):
    now = datetime.now().date()
    file_date = datetime.fromtimestamp(os.path.getmtime("manager.err")).date()
    if file_date != now:
        self.logger.debug("Date changed with no events - rotating the log...")
        self._errhandler.doRollover()
rotate_log_if_new_day()函数在管理器的更新周期(每15分钟)中被调用,这保证日志会在午夜之前的15分钟内旋转。如果日志已经旋转过了(例如:已经记录了一个错误或已经手动旋转),它将不执行任何操作。

最初我设置了一个保护措施,以防止在日期未更改时调用os.path...,但是通过timeit()测试发现缓存当前日期(1.85μs vs 5.7μs)并验证是否需要采取任何措施,几乎没有加速效果。


1

看起来TimedRotatingFileHandler没有你需要的功能。你可以尝试以下函数,在特定时间旋转日志文件。

def log_rollover(folder_path):
    # folder_path: the absolute path to your log folder 
    today = str(datetime.date.today()).replace('-', '')
    list_of_files = os.listdir(folder_path)
    for log_file in list_of_files:
        file_path = folder_path + '/' + log_file
        if log_file.endswith('.log') and os.stat(file_path).st_size > 0:
            new_file_path = file_path.split('.')[-2] + '-' + today + '.log'
            subprocess.check_call(['cp', file_path, new_file_path])
            subprocess.check_call(['gzip', new_file_path])
            subprocess.check_call(['cp', '/dev/null', file_path]) 

你需要使用定时任务来在特定时间运行函数,APScheduler 是一个不错的选择。例如,如果你想在凌晨3点运行定时任务,可以使用以下代码:
folderPath = '/var/log/app'  # The path to your log folder
scheduler = BlockingScheduler()
scheduler.add_job(log_rollover, trigger='cron', args=[folderPath], hour=3, minute=0)
scheduler.start()

不要忘记为 APScheduler 设置时区。

谢谢。这看起来很有用。我会试一试的。 - tamjd1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接