4

我的应用程序在相当长的一段时间内管理多个对象(称为请求)的状态。每个请求都有一个唯一标识符,并经历不同的生命周期。随着时间的推移,系统中会出现新的请求。

我想为每个请求编写一个单独的日志文件。日志将跟踪该请求状态的每一个有趣的变化。因此,如果我想了解有关 Request X 历史的所有信息,只需查看 X.log 即可。

显然,我可以使用纯文件手动推出解决方案。但我想用 Python 的日志框架来做到这一点。一种方法是为每个唯一请求创建一个新的记录器实例,将其配置为指向正确的文件,然后注销。但这感觉像是错误的解决方案。它创建了许多记录器,这些记录器不是垃圾收集的,而且也是无限的,因为新的请求将继续进入系统。

我希望有某种方法来配置单个记录器,可能使用自定义处理程序,以便我可以根据传入请求的 ID 将输出重定向到不同的文件。我查看了文档,但我看到的所有内容似乎都在传入记录的级别上工作,而不是操纵传出端点。

这可能吗?

4

2 回答 2

2

查看logging.handlers中RotatingFileHandler的代码最终给了我足够的线索来解决这个问题。关键实现是,当记录一条消息时,可以传递一个可选关键字,这是一个要存储在. 这可以从. 在 中,我们可以根据用户提供的值触发输出流的变化。extraRecordHandlerHandler

import logging

class MultiFileHandler(logging.FileHandler):

    def __init__(self, filename, mode, encoding=None, delay=0):
        logging.FileHandler.__init__(self, filename, mode, encoding, delay)

    def emit(self, record):
        if self.should_change_file(record):
            self.change_file(record.file_id)
        logging.FileHandler.emit(self, record)

    def should_change_file(self, record):
        if not hasattr(record, 'file_id') or record.file_id == self.baseFilename:
             return False
        return True

    def change_file(self, file_id):
        self.stream.close()

        self.baseFilename = file_id
        self.stream = self._open()

if __name__ == '__main__':

    logger = logging.getLogger('request_logger')
    logger.setLevel(logging.DEBUG)    
    handler = MultiFileHandler(filename='out.log', mode='a')
    handler.setLevel(logging.DEBUG)    
    logger.addHandler(handler)

    # Log some messages to the original file
    logger.debug('debug message')
    logger.info('info message')

    # Log some messages to a different file
    logger.debug('debug message',       extra={'file_id':'changed.log'})
    logger.info('info message',         extra={'file_id':'changed.log'})
    logger.warn('warn message',         extra={'file_id':'changed.log'})
    logger.error('error message',       extra={'file_id':'changed.log'})
    logger.critical('critical message', extra={'file_id':'changed.log'})
于 2013-04-05T06:29:26.493 回答
0

听起来您正在寻找一个完全不同的日志系统——一个不维护任何全局状态的系统。你看过日志吗?

或者,如果您必须避免第三方依赖项,您可以使用logging.addLevelName为每个请求添加一个级别,并添加一个带有过滤器的处理程序,该过滤器将每个不匹配的日志条目丢弃到每个请求的记录器中。一旦请求超出范围,您可以调用处理程序的close方法将其从树中删除。

然而,这可能不会很好地扩展,因为每个处理程序的过滤器都会为每条日志消息调用。

于 2013-04-05T01:29:02.307 回答