将消息从两个模块记录到不同的文件,并包括使用其他日志记录工具的模块记录

时间:2014-11-25 16:27:35

标签: python logging

我有一个导入两个模块的脚本 - mailserver.pyclient.py。其中每个都有一个方法,类似于:

def startLogger(logPath):
    log.discardLogs()
    d = os.path.dirname(logPath)
    if not os.path.exists(d):
        os.makedirs(d)
    log.startLogging(open(logPath, 'a'))

然后我使用与mailserver.pyclient.py不同的参数调用该函数,但它们最终会覆盖彼此的设置(因此最后一次调用获胜)。

显然,我可以根据Logging Cookbook使用多个记录器。是什么阻止了我

  • 各种下游脚本/模块使用其他一些日志工具(例如Twisted和smtplib的内部工具)
  • 某些设施只能使用“默认”目的地

所以我猜这些日志条目会丢失,除非我创建了一组广泛的重写代码。

问题是:为mailserver.pyclient.py及其所有相关模块设置两个日志记录目标的最佳做法是什么?

1 个答案:

答案 0 :(得分:1)

不要过度复杂化。尽可能使用单一的日志工具。

一个理智的日志记录工具(包括logging)不要求每个模块指定日志位置等 - 它们只需要在某个专用位置指定(例如在主模块中)。

所以使用一个。对于logging,在导入的模块中,这就像

一样简单
l=logging.getLogger('<distinguishing name>')
#use l's methods

如果您想同时使用loggingtwisted进行登录,最好写一个logging Handler,将邮件复制到Twisted。

示例:调整外国设施

在我之前的一个项目(使用smtplibsmtpd的SMTP代理)中,这是 我如何在logging

下编织各种日志工具
import logging    
l = logging.getLogger() #root logger to be used in the main module
f = logging.Formatter('%(asctime)s %(process)d:%(thread)d %(name)s %(levelname)-8s %(message)s')
<set log file, install an excepthook to log unhandled exceptions>
class LogStream(smtpd.Devnull):
    """A write-only stream-like interface to logging module.
    write() and flush() are the public interface"""
    def __init__(self,name=None,level=logging.DEBUG):
    def write(self,s):
        """log the data, line-buffered; uses flush() with argument internally"""
    def flush(self,p=None):
        """log and remove `p' (default - all) bytes from the buffer.
        The `p' parameter is not a part of the public interface"""

class asyncore_logger:
    <some settings>
    @classmethod
    def log(cls,msg,level='info'):
        """A compatible replacement for asyncore.dispatcher.log_info.
        The class is only needed as a settings container"""

smtpd.DEBUGSTREAM=LogStream('smtpd')
#smtpd logs receipts but not replies
smtpd.SMTPChannel.push=<custom_wrapper_using_DEBUGSTREAM>(smtpd.SMTPChannel.push)
smtplib.stderr=LogStream('smtplib')
asyncore.dispatcher.log_info = asyncore_logger.log
#clean up entries that are no longer needed in the local namespace
del LogStream, asyncore_logger, <custom_wrapper_using_DEBUGSTREAM>

有了这个,我有一个日志文件,其中包含来自我的程序smtplibsmtpdasyncore的消息,这些消息已正确标记(%(name)s字段)。

使用logging

记录到多个文件

创建多个Handler并将Filter附加到需要仅包含特定邮件的用户。要通过源库区分,您可能会按name进行过滤。