使用多进程记录到python中的一个文件

时间:2018-09-25 17:35:15

标签: python python-3.x python-2.7 logging multiprocessing

我正在尝试使用QueueHandler在多个进程之间设置日志记录。我在多次打印的日志文件中看到同一条日志。将其用作模板(https://docs.python.org/3/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes

编辑

多重处理文件:

import logging
from logging.handlers   import RotatingFileHandler, QueueHandler
from multiprocessing import Process
from queue import Empty

class MultiProcessQueueLoggingListner(Process):
    def __init__(self, name, queue):
        super().__init__()
        self.name = name
        self.queue = queue
        self.logger = logging.getLogger(name)
        self.file_handler = RotatingFileHandler(name, maxBytes=536870912, backupCount=2)
        self.formatter = logging.Formatter('%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s')
        self.file_handler.setFormatter(self.formatter)
        self.logger.addHandler(self.file_handler)

    def run(self):
        while True:
            try:
                record = self.queue.get()
                if record is None:
                    break
                self.logger.handle(record)
            except Exception:
                import sys, traceback
                print('Whoops! Problem:', file=sys.stderr)
                traceback.print_exc(file=sys.stderr)


class MulitProcessQueueLogger(object):
def __init__(self, name, queue):
    self.name = name
    self.queue = queue
    self.queue_handler = QueueHandler(queue)
    self.logger = logging.getLogger(name)
    self.logger.addHandler(self.queue_handler)
    self.logger.setLevel(logging.DEBUG)

测试文件:

import multi_process_logging
import multiprocessing
from time import sleep


def worker(po):
    name = multiprocessing.current_process().name
    po = multi_process_logging.MulitProcessQueueLogger('test.log', q)
    print("In worker")
    for i in range(10):
        po.logger.info(f"Logging from {name} line {i}")
    po.queue.put(None)

def main():
    q = multiprocessing.Queue()
    lp = multi_process_logging.MultiProcessQueueLoggingListner('test.log', q)
    lp.start()
    p = multiprocessing.Process(target=worker, args=(q,))
    p.start()
    p.join()
    lp.join()



if __name__ == '__main__':
    main()

我看到的问题是test.log文件包含同一条目的多行。该程序现在停止,并且不会无限期运行,但仍然会看到多行

    cat test.log | grep 'line 0'
2018-09-26 16:32:40,117 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:40,117 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:40,117 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:40,117 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:50,318 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:50,318 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:50,318 Process-2  test.log INFO     Logging from Process-2 line 0
2018-09-26 16:32:50,318 Process-2  test.log INFO     Logging from Process-2 line 0

我在运行前删除了test.log,以排除将其追加到现有日志文件中的情况,但仍然看到多个日志。

谢谢

2 个答案:

答案 0 :(得分:1)

您的问题是由以下事实引起的:您正在检查是否None脱离循环,但这永远不会发生,因为QueueHandler总是将LogRecord写入队列,切勿None。如果要将None写到队列中,则需要直接写,而不要写po.logger.info(None)。例如,将队列存储为queue实例的名为MulitProcessQueueLogger的属性,然后在po.queue.put(None)中执行worker()

答案 1 :(得分:0)

我意识到这不是一个“具体细节”的答案,但如果实际上主要是为了实现多进程、相同日志文件的日志记录,那么可能比找到一个有效的现成工具还要糟糕解决方案:concurrent-log-handler 似乎是一个成熟的项目,据我所知似乎工作得很好。我只需要更改我的 logging.conf 文件中的一行即可实现目标。

毫无疑问,如果有兴趣,可以检查那里的源代码以查看他们使用的“具体细节”。