在python中使用多进程记录到一个文件
我正在尝试使用QueueHandler在多个进程之间设置日志记录。我在多次打印的日志文件中看到相同的日志。将此用作模板() 编辑 多处理文件:在python中使用多进程记录到一个文件,python,python-3.x,python-2.7,logging,multiprocessing,Python,Python 3.x,Python 2.7,Logging,Multiprocessing,我正在尝试使用QueueHandler在多个进程之间设置日志记录。我在多次打印的日志文件中看到相同的日志。将此用作模板() 编辑 多处理文件: import logging from logging.handlers import RotatingFileHandler, QueueHandler from multiprocessing import Process from queue import Empty class MultiProcessQueueLoggingListner
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,以排除附加到现有日志文件的可能性,但仍然可以看到多个日志
谢谢您的问题是因为您正在检查一个
None
来打破循环,但这永远不会发生,因为QueueHandler
总是将LogRecord
写入队列,而不是None
。如果要将None
写入队列,则需要直接写入,而不是执行po.logger.info(None)
。例如,将队列存储为MulitProcessQueueLogger
实例的名为queue
的属性,然后在worker()中执行po.queue.put(None)
,我意识到这不是一个“螺母和螺栓”答案,但如果实际上主要是为了实现多进程、相同的日志文件记录,有人可能比找到一个有效的现成解决方案更糟糕:就我所知,这似乎是一个成熟的项目,而且似乎工作得很好。我只需更改logging.conf文件中的一行即可实现此目标
毫无疑问,如果有人感兴趣,可以检查那里的源代码,查看他们使用的“螺母和螺栓”。我添加了您提到的更改,现在我看到它停止了,但仍然看到同一条目的多行代码。我把处理程序搞乱了吗?@Greg Brown这是因为你还必须在新进程中而不是在父进程中初始化记录器。您的日志记录程序继承了QueueHandler,因此他在处理日志记录时会将其重新排入队列。@Darkonaut我将日志记录程序移到了进程中,而不是主进程中,但仍能看到重复的日志条目。我遗漏了什么吗?@Greg Brown\uuuuu init\uuuu
在父级中运行,您必须将记录器的配置重新定位到run
。制作一个\u init\u logging
方法,并从run
@Darkonaut调用它,进行了更改,现在可以工作了,谢谢。