Python:在不同的文件中记录不同的数据,而不会丢失模块名称

Python:在不同的文件中记录不同的数据,而不会丢失模块名称,python,python-3.x,logging,Python,Python 3.x,Logging,我有一个带有主脚本(main.py)和几个模块(mod1.py、mod2.py等)的程序 在main.py中,我配置了一个根记录器,以便在终端和文件中写入消息 # main.py import logging LOG = logging.getLogger() def init_logger(): """...""" if __name__ == '__main__': init_logger() LOG.info("...") 在其他模块中,我使用标准的习惯用法:

我有一个带有主脚本(main.py)和几个模块(mod1.py、mod2.py等)的程序

在main.py中,我配置了一个根记录器,以便在终端和文件中写入消息

# main.py
import logging
LOG = logging.getLogger()

def init_logger():
    """..."""

if __name__ == '__main__':
    init_logger()
    LOG.info("...")
在其他模块中,我使用标准的习惯用法:

# mod1.py
import logging
LOG = logging.getLogger(__name__)
一切正常,对于日志文件中的每一行,我知道它来自哪个模块。例如,我的日志文件包含以下内容:

(...)
13:52:59 [INFO |root] (MainThread) Logger initialized (/some_path/logs/log.txt)
13:53:00 [DEBUG|mod1] (MainThread) Some message
13:53:01 [INFO |mod234] (thread_1) Some other message
(...)
但现在,我希望将一些非常具体的消息记录在一个单独的文件中。我不希望它污染我现有的日志文件,我仍然想知道消息的来源(我想我必须保留一个根日志)

我不想按级别(调试、信息、错误等)过滤,但我想按某种类别过滤

我如何做到这一点?

我的init_logger函数仅供记录,但我不确定它是否相关:


如果希望保持相同的结构,可以创建两个文件记录器,并为每个记录器分配不同的筛选器。根记录器将筛选出非常特定的消息,而另一个记录器只考虑那些相同的消息。那么,最重要的是你想过滤什么。假设它是内容,它将像创建过滤器一样简单:

import logging

class ContentFilter(logging.Filter):

    def __init__(self, content, name="", exclude=False):
        super(ContentFilter, self).__init__(name)
        self.content = content
        self.exclude = exclude  # allow for exclusion behavior as well

    def filter(self, record):
        if record.msg:  # ignore empty logs
            if self.content in record.msg:  # note: you can filter on other `record` fields...
                return not self.exclude
        return self.exclude
然后,在设置日志记录时,请确保一个文件记录器的
ContentFilter
设置为filter-in,而另一个文件记录器的设置为filter-out,并且一切正常。例如:

log = logging.getLogger()  # init the root logger
log.setLevel(logging.DEBUG)  # make sure we capture all levels for our test

# make a formatter to use for the file logs, shortened version from yours...
formatter = logging.Formatter("%(asctime)s [%(levelname)-5s|%(name)s] %(message)s")

# first file handler:
handler = logging.FileHandler("log1.log")  # create a 'log1.log' handler
handler.setLevel(logging.DEBUG)  # make sure all levels go to it
handler.setFormatter(formatter)  # use the above formatter
handler.addFilter(ContentFilter("special content", exclude=True))  # exclude 'special content'
log.addHandler(handler)  # add the file handler to the root logger

# second file handler:
handler = logging.FileHandler("log2.log")  # create a 'log2.log' handler
handler.setLevel(logging.DEBUG)  # make sure all levels go to it
handler.setFormatter(formatter)  # use the above formatter
handler.addFilter(ContentFilter("special content"))  # include only 'special content'
log.addHandler(handler)  # add the file handler to the root logger
设置完成后,您可以通过以下方式进行测试:

# first create a few fake 'module' loggers for a good measure:
log1 = logging.getLogger("module1")
log2 = logging.getLogger("module2")
log3 = logging.getLogger("module3")

log.info("Root logger without that content...")
log.info("Root logger with the special content...")

log1.info("Module1 logger without that content...")
log1.info("Module1 logger with the special content...")

log2.info("Module2 logger without that content...")
log2.info("Module2 logger with the special content...")

log3.info("Module3 logger without that content...")
log3.info("Module3 logger with the special content...")
这将导致创建两个文件,
log1.log
包含:

2018-07-17 16:21:19,780 [INFO |root] Root logger without that content... 2018-07-17 16:21:19,781 [INFO |module1] Module1 logger without that content... 2018-07-17 16:21:19,781 [INFO |module2] Module2 logger without that content... 2018-07-17 16:21:19,782 [INFO |module3] Module3 logger without that content... 2018-07-17 16:21:19,781 [INFO |root] Root logger with the special content... 2018-07-17 16:21:19,781 [INFO |module1] Module1 logger with the special content... 2018-07-17 16:21:19,781 [INFO |module2] Module2 logger with the special content... 2018-07-17 16:21:19,782 [INFO |module3] Module3 logger with the special content...
根据内容(或缺少内容)将单个日志消息有效地重定向到不同的文件。

如果要保持相同的结构,可以创建两个文件记录器,并为每个日志消息分配不同的筛选器。根记录器将筛选出非常特定的消息,而另一个记录器只考虑那些相同的消息。那么,最重要的是你想过滤什么。假设它是内容,它将像创建过滤器一样简单:

import logging

class ContentFilter(logging.Filter):

    def __init__(self, content, name="", exclude=False):
        super(ContentFilter, self).__init__(name)
        self.content = content
        self.exclude = exclude  # allow for exclusion behavior as well

    def filter(self, record):
        if record.msg:  # ignore empty logs
            if self.content in record.msg:  # note: you can filter on other `record` fields...
                return not self.exclude
        return self.exclude
然后,在设置日志记录时,请确保一个文件记录器的
ContentFilter
设置为filter-in,而另一个文件记录器的设置为filter-out,并且一切正常。例如:

log = logging.getLogger()  # init the root logger
log.setLevel(logging.DEBUG)  # make sure we capture all levels for our test

# make a formatter to use for the file logs, shortened version from yours...
formatter = logging.Formatter("%(asctime)s [%(levelname)-5s|%(name)s] %(message)s")

# first file handler:
handler = logging.FileHandler("log1.log")  # create a 'log1.log' handler
handler.setLevel(logging.DEBUG)  # make sure all levels go to it
handler.setFormatter(formatter)  # use the above formatter
handler.addFilter(ContentFilter("special content", exclude=True))  # exclude 'special content'
log.addHandler(handler)  # add the file handler to the root logger

# second file handler:
handler = logging.FileHandler("log2.log")  # create a 'log2.log' handler
handler.setLevel(logging.DEBUG)  # make sure all levels go to it
handler.setFormatter(formatter)  # use the above formatter
handler.addFilter(ContentFilter("special content"))  # include only 'special content'
log.addHandler(handler)  # add the file handler to the root logger
设置完成后,您可以通过以下方式进行测试:

# first create a few fake 'module' loggers for a good measure:
log1 = logging.getLogger("module1")
log2 = logging.getLogger("module2")
log3 = logging.getLogger("module3")

log.info("Root logger without that content...")
log.info("Root logger with the special content...")

log1.info("Module1 logger without that content...")
log1.info("Module1 logger with the special content...")

log2.info("Module2 logger without that content...")
log2.info("Module2 logger with the special content...")

log3.info("Module3 logger without that content...")
log3.info("Module3 logger with the special content...")
这将导致创建两个文件,
log1.log
包含:

2018-07-17 16:21:19,780 [INFO |root] Root logger without that content... 2018-07-17 16:21:19,781 [INFO |module1] Module1 logger without that content... 2018-07-17 16:21:19,781 [INFO |module2] Module2 logger without that content... 2018-07-17 16:21:19,782 [INFO |module3] Module3 logger without that content... 2018-07-17 16:21:19,781 [INFO |root] Root logger with the special content... 2018-07-17 16:21:19,781 [INFO |module1] Module1 logger with the special content... 2018-07-17 16:21:19,781 [INFO |module2] Module2 logger with the special content... 2018-07-17 16:21:19,782 [INFO |module3] Module3 logger with the special content...
根据日志消息的内容(或缺少内容),有效地将单个日志消息重定向到不同的文件。

定义第二个日志如何?请看,我已经为每个模块使用了一个记录器(
LOG=logging.getLogger(\uuu name\uuuu)
),但它们都依赖于根记录器,根记录器是我配置的一个,有2个处理程序,我希望保留此机制以了解哪个模块正在记录日志。定义第二个记录器如何?请看,我已经为每个模块使用了一个记录器(
LOG=logging.getLogger(\uuuu name\uuuuu)
),但它们都依赖于根记录器,根记录器是我配置了2个处理程序的一个,我希望保留此机制以了解哪个模块正在进行日志记录。