Сельдерей по умолчанию logging.FileHandler
- это WatchedFileHandler
.Мы хотим использовать TimedRotatingFileHandler
от logging.handlers
.Поэтому мы используем сигнал сельдерея after_setup_logger
в нашем файле задач для выполнения следующих действий:
from celery.signals import after_setup_logger
@after_setup_logger.connect
def replace_handler(**kwargs_):
logger = kwargs_['logger'] if 'logger' in kwargs_ else None
if logger and logger.handlers:
handler_celery = logger.handlers[-1]
handler = TimedRotatingFileHandler(handler_celery.baseFilename, 'midnight', 1)
handler.setFormatter(handler_celery.formatter)
logger.handlers[-1] = handler
Теперь при этом сбрасываются как рабочий, так и логгер ударов.Я проверил это, используя 2-минутные интервалы в конструкторе TimedRotatingFileHandler
, поэтому я предполагаю, что он работает для ночной ротации.
EDIT1: 25/09/2019
СпасибоТомашу Линхарту - я посмотрю в logrotate
.Я сегодня занимался кодированием, поэтому я проверил, что журнал действительно вращается за ночь.Я также немного обновил код, чтобы он стал немного безопаснее.У меня довольно простая настройка: параллелизм = 1, где мне нужна очередь задач FIFO для последовательной обработки, поэтому, возможно, это простое решение маскирует потенциальные проблемы, указанные Томашем.
РЕДАКТИРОВАТЬ 2: 25/09/ 2019
Я потратил время на изучение этого вопроса.Есть еще несколько проблем: WatchedFileHandler
- это только linux, и он может страдать от условий гонки, в то время как сам logrotate
также может страдать от условий гонки.https://docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes объясняет многопроцессное ведение журнала, а https://docs.python.org/3/howto/logging-cookbook.html объясняет, как использовать QueueListener
вместо создания собственного multiprocessing.Process
.Собрав все это вместе, я создал многопроцессорную оболочку класса для TimedRotatingFileHandler
:
import logging
from logging.handlers import QueueHandler, QueueListener, TimedRotatingFileHandler
from multiprocessing import Queue as MQueue
from celery.signals import after_setup_logger
class QueuedTimedRotatingFileHandler:
instance = None
def __init__(self, filename_, formatter_):
self.queue = MQueue(-1)
handler = TimedRotatingFileHandler(filename_, 'midnight', 1)
handler.setFormatter(formatter_)
self.listener = QueueListener(self.queue, handler)
self.listener.start()
def __del__(self):
self.listener.stop()
@after_setup_logger.connect
def replace_handler(**kwargs_):
logger = kwargs_['logger'] if 'logger' in kwargs_ else None
if logger and logger.handlers:
handler_celery = logger.handlers[-1]
if QueuedTimedRotatingFileHandler.instance is None:
QueuedTimedRotatingFileHandler.instance = \
QueuedTimedRotatingFileHandler(
handler_celery.baseFilename,
handler_celery.formatter
)
handler = QueueHandler(QueuedTimedRotatingFileHandler.instance.queue)
logger.handlers[-1] = handler
Теперь это похоже на самое безопасное и элегантное кроссплатформенное решение.Любые комментарии приветствуются.
EDIT3: 26/09/2019
Последнее изменение, я думаю, изменил код выше.Требуется создать оболочку, как синглтон, потому что работник сельдерея может анализировать файл несколько раз.