”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 如何在 Python 中实现多处理感知日志记录:基于队列的解决方案?

如何在 Python 中实现多处理感知日志记录:基于队列的解决方案?

发布于2024-11-03
浏览:571

  How to Implement Multiprocessing-Aware Logging in Python: A Queue-Based Solution?

如何在 Python 中实现多处理感知日志记录

Python 中的多处理允许创建独立运行的多个进程。但是,访问日志文件等共享资源可能会变得复杂,因为多个进程可能会尝试同时写入这些资源。

为了避免此问题,Python 多处理模块提供了模块级多处理感知日志记录功能。这使得记录器能够通过确保一次只有一个进程写入特定文件描述符来防止日志消息出现乱码。

但是,框架内的现有模块可能不支持多处理感知,从而导致需要寻求替代解决方案。一种方法涉及创建一个自定义日志处理程序,通过管道将日志消息发送到父进程。

下面提供了此方法的实现:

from logging.handlers import RotatingFileHandler
import multiprocessing, threading, logging, sys, traceback

class MultiProcessingLog(logging.Handler):
    def __init__(self, name, mode, maxsize, rotate):
        logging.Handler.__init__(self)

        # Set up the file handler for the parent process
        self._handler = RotatingFileHandler(name, mode, maxsize, rotate)
        
        # Create a queue to receive log messages from child processes
        self.queue = multiprocessing.Queue(-1)
        
        # Start a thread in the parent process to receive and log messages
        t = threading.Thread(target=self.receive)
        t.daemon = True
        t.start()

    def receive(self):
        while True:
            try:
                # Get a log record from the queue
                record = self.queue.get()
                
                # Log the record using the parent process's file handler
                self._handler.emit(record)
            # Exit the thread if an exception is raised
            except (KeyboardInterrupt, SystemExit):
                raise
            except EOFError:
                break
            except:
                traceback.print_exc(file=sys.stderr)

    def send(self, s):
        # Put the log record into the queue for the receiving thread
        self.queue.put_nowait(s)

    def _format_record(self, record):
        # Stringify any objects in the record to ensure that they can be sent over the pipe
        if record.args:
            record.msg = record.msg % record.args
            record.args = None
        if record.exc_info:
            dummy = self.format(record)
            record.exc_info = None
            
        return record

    def emit(self, record):
        try:
            # Format and send the log record through the pipe
            s = self._format_record(record)
            self.send(s)
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

    def close(self):
        # Close the file handler and the handler itself
        self._handler.close()
        logging.Handler.close(self)

此自定义日志处理程序允许框架内的模块使用标准日志记录实践,而无需本身具有多处理意识。日志消息通过管道从子进程发送到父进程,确保日志消息不乱码并正确写入日志文件。

最新教程 更多>

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3