Python-芹菜原木

Python-Celery Log

我用烧瓶,python 3.x 和 celery4 (总共 8 个工人)

我想制作 'RotatingFileHandler' 的日志文件,以便在文件大小超过时拆分。

它在第一个日志文件中工作正常。 (包含所有worker日志,PoolWorker-1 ~ PoolWorker-8)

-rw-rw-r-- 1 sj sj   1048530  9월 18 10:01 celery_20170918.log (All worker's log)

但是当文件大小超过时,工作人员将日志写入单独的文件。

-rw-rw-r-- 1 sj sj    223125  9월 18 10:47 celery_20170918.log  (All worker's log except below 2, 5, 6))
-rw-rw-r-- 1 sj sj     43785  9월 18 10:47 celery_20170918.log.1 (only PoolWorker-2 log)
-rw-rw-r-- 1 sj sj     46095  9월 18 10:47 celery_20170918.log.2 (only PoolWorker-5 log)
-rw-rw-r-- 1 sj sj     45990  9월 18 10:47 celery_20170918.log.3 (only PoolWorker-6 log)
-rw-rw-r-- 1 sj sj   1048530  9월 18 10:01 celery_20170918.log.4 (Log file made at first is changed to this.)

我不知道规则是什么,他们有任何重复的日志..!!!

我的芹菜记录器如下。

tasks.py

logger = get_task_logger('tasks')
logger.setLevel("INFO")
filename = './log/celery/celery_task.log'
formatter = Formatter('%(levelname)s-%(asctime)s %(processName)s %(funcName)s():%(lineno)d %(message)s')
# FileSize rotating
fileMaxByte = 1024 * 1024 * 1  # 30MB
fileHandler = logging.handlers.RotatingFileHandler(filename, maxBytes=fileMaxByte, backupCount=100)
fileHandler.setFormatter(formatter)
logger.addHandler(fileHandler)

@celery.task(...options...)
def test_call(self):
    logger.info("LOG TEST")

test.py

if __name__ == '__main__':
    test_call.apply_async()

怎么了?

RotatingFileHandler 日志文件翻转时不保持多进程之间的原子性。

在多进程环境中,进程 A 在日志文件 c.log 上看到 maxBytes,将文件重命名为 c.log.1,然后将一些日志行写入新创建的 [=12] =].

但与此同时,另一个进程B可能仍然持有c.log的句柄,因为the way used to check file size, is based on the end offset of file handle, it also sees maxBytes reached, want to do file roll over on its own, because the way used to roll over是磁盘上的重命名文件,此进程尝试将c.log重命名为c.log.1,但由于 c.log.1 存在,重命名为 c.log.2

由于还有其他进程,c.log.3 被创建等等。

这个问题可以通过使用外部日志记录机制得到很好的解决,或者您可以包装自己的原子文件旋转日志记录处理程序。