本文介绍了记录模块示例代码每次调用重复消息n次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我对Python的日志记录模块的输出感到惊讶。我写了Python.org的记录方法 。当我运行示例代码时,会有很多(令人困惑的)重复。 I'm surprised by the output from Python's logging module. I wrote up the Python.org's How-To for Logging. When I run the sample code, there is a lot of (confusing) duplication. StreamHandler复制日志消息,每次我使用魔法%run 重新加载iPython中的文件时The StreamHandler duplicates the log messages, one for each time I reload the file in iPython with the magic %runIn [4]: %run main.py2018-05-11 2127:33 - WARNING - 3. This is a warning, yous!2018-05-11 2127:33 - ERROR - 4. Here is an error2018-05-11 2127:33 - CRITICAL - 5. This is f-ing critical![...]In [7]: %run main.py2018-05-11 2127:38 - WARNING - 3. This is a warning, yous!2018-05-11 2127:38 - WARNING - 3. This is a warning, yous!2018-05-11 2127:38 - WARNING - 3. This is a warning, yous!2018-05-11 2127:38 - ERROR - 4. Here is an error2018-05-11 2127:38 - ERROR - 4. Here is an error2018-05-11 2127:38 - ERROR - 4. Here is an error2018-05-11 2127:38 - CRITICAL - 5. This is f-ing critical!2018-05-11 2127:38 - CRITICAL - 5. This is f-ing critical!2018-05-11 2127:38 - CRITICAL - 5. This is f-ing critical!我添加了一个FileHandler:I added a FileHandler:fh = logging.FileHandler("app.log")fh.setLevel(logging.DEBUG)fh.setFormatter(formatter)logger.addHandler(fh)这也重复:xtian@spaceghost> cat app.log2018-05-11 2159:24 - WARNING - 3. This is a warning!2018-05-11 2159:24 - ERROR - 4. This is an error2018-05-11 2159:24 - CRITICAL - 5. This is fucking critical![...]2018-05-11 2201:00 - WARNING - 3. This is a warning, yous!2018-05-11 2201:00 - WARNING - 3. This is a warning, yous!2018-05-11 2201:00 - WARNING - 3. This is a warning, yous!2018-05-11 2201:00 - ERROR - 4. Here is an error.2018-05-11 2201:00 - ERROR - 4. Here is an error.2018-05-11 2201:00 - ERROR - 4. Here is an error.2018-05-11 2201:00 - CRITICAL - 5. This is f-ing critical!2018-05-11 2201:00 - CRITICAL - 5. This is f-ing critical!2018-05-11 2201:00 - CRITICAL - 5. This is f-ing critical!我也遵循了 other 帖子,并在消息调用之前添加这些行:I also followed the suggestions from other posts, and added these lines just before the message calls:# propagation fixlogger.propagate = False结果相同。设置发布,我看到类似的问题:Setting up to post, I see a similar question: 什么可能导致日志记录模块记录多次记录? 但所有这些调试都是针对OP的原始自定义代码。我的问题是示例代码,我希望它可以警告或更好地解释发生了什么。 But all this debugging is for the OP's original custom code. My issue is with the sample code, which I expect should warn or explain better what's happening. 文档说, 注意。如果您将处理程序附加到记录器及其一个或多个祖先,它可能会多次发出相同的记录。一般来说,你不应该需要将处理程序附加到多个记录器 - 如果你只是将附加到记录器层次结构中最高的适当记录器,那么它会看到所有后代记录器记录的所有事件,提供表示其传播设置保留为True。一个常见的场景是将处理程序仅附加到根记录器,并让传播来处理其余部分。 Note. If you attach a handler to a logger and one or more of its ancestors, it may emit the same record multiple times. In general, you should not need to attach a handler to more than one logger - if you just attach it to the appropriate logger which is highest in the logger hierarchy, then it will see all events logged by all descendant loggers, provided that their propagate setting is left set to True. A common scenario is to attach handlers only to the root logger, and to let propagation take care of the rest.您可以看到完整的测试文件 main.py 此处查看我是否有'多个记录器'。You can see the full test file main.py here to see if I have 'more than one logger'.import logging# Root Loggerlogger = logging.getLogger(__name__)# Console handlerch = logging.StreamHandler()ch.setLevel(logging.WARNING)# Formatterformatter = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(message)s' , datefmt='%Y-%m-%d %H%M:%S', style='%')# Add formatter to Console handler chch.setFormatter(formatter)# Add ch to loggerlogger.addHandler(ch)# Text File handlerfh = logging.FileHandler("app.log")fh.setLevel(logging.DEBUG)fh.setFormatter(formatter)logger.addHandler(fh)# propagation fixlogger.propagate = False# Example Application codelogger.debug("1. This is a debug message.")logger.info("2. This is an info message.")logger.warning('3. This is a warning!')logger.error('4. This is an error')logger.critical("5. This is fucking critical!") 推荐答案 logging.getLogger(__ name __)返回 logger 每次执行%run main.py 时都是相同的记录器。但是The logger returned by logging.getLogger(__name__) is the same logger each time %run main.py is executed. But ch = logging.StreamHandler()每次实例化一个新的StreamHandler,然后将其添加到记录器:instantiates a new StreamHandler each time, which is then added to the logger:logger.addHandler(ch)因此,在后续运行%run main.py , logger 附加了多个处理程序,并且每个处理程序都会发出一条记录。Thus, on subsequent runs of %run main.py, the logger has multiple handlersattached to it and a record gets emitted by each handler.In [5]: %run main.py2018-05-11 2251:17 - WARNING - 3. This is a warning!2018-05-11 2251:17 - ERROR - 4. This is an error2018-05-11 2251:17 - CRITICAL - 5. This is fucking critical!In [6]: loggerOut[6]: <logging.Logger at 0x7f5d0152fe10>第一次%运行main.py 运行时,两个处理程序附加到 logger :The first time %run main.py is run, two handlers are attached to logger:In [7]: logger.handlersOut[12]: [<logging.StreamHandler at 0x7f5d0152fdd8>, <logging.FileHandler at 0x7f5d014c40f0>]In [13]: %run main.py2018-05-11 2251:44 - WARNING - 3. This is a warning!2018-05-11 2251:44 - WARNING - 3. This is a warning!2018-05-11 2251:44 - ERROR - 4. This is an error2018-05-11 2251:44 - ERROR - 4. This is an error2018-05-11 2251:44 - CRITICAL - 5. This is fucking critical!2018-05-11 2251:44 - CRITICAL - 5. This is fucking critical!第二次,现在有四个处理程序:The second time, there are now four handlers:In [14]: logger.handlersOut[14]: [<logging.StreamHandler at 0x7f5d0152fdd8>, <logging.FileHandler at 0x7f5d014c40f0>, <logging.StreamHandler at 0x7f5d014c4668>, <logging.FileHandler at 0x7f5d014c4550>]In [15]: loggerOut[15]: <logging.Logger at 0x7f5d0152fe10> 为了防止重复,您可以调用 logger.removeHandler %run 来电:To prevent duplication, you could call logger.removeHandler between %run calls:In [29]: for handler in logger.handlers: logger.removeHandler(handler)In [30]: %run main.py2018-05-11 2257:30 - WARNING - 3. This is a warning!2018-05-11 2257:30 - ERROR - 4. This is an error2018-05-11 2257:30 - CRITICAL - 5. This is fucking critical!或修改 main.py 以便每次调用%run 时,都不会附加新的处理程序。 例如,您可以使用 logger logging.config.dictConfigrel =nofollow noreferrer> logging.config.dictConfig :or, modify main.py so that new handlers are not attached each time %run is called.For example, you could setup logger using logging.config.dictConfig:import loggingimport logging.config# Modified using https://stackoverflow.com/a/7507842/190597 as a templatelogging_config = { 'version': 1, 'formatters': { 'standard': { 'format': '%(asctime)s - %(levelname)s - %(message)s' }, }, 'handlers': { 'stream': { 'level': 'INFO', 'formatter': 'standard', 'class': 'logging.StreamHandler', }, 'file': { 'level': 'DEBUG', 'formatter': 'standard', 'class': 'logging.FileHandler', 'filename': 'app.log' }, }, 'loggers': { __name__: { 'handlers': ['stream', 'file'], 'level': 'WARN', 'propagate': False }, } }logging.config.dictConfig(logging_config)logger = logging.getLogger(__name__)# Example Application codelogger.debug("1. This is a debug message.")logger.info("2. This is an info message.")logger.warning('3. This is a warning!')logger.error('4. This is an error')logger.critical("5. This is fucking critical!")使用此代码,%run main.py 每次都会发出相同的输出。Using this code, %run main.py emits the same output each time. 这篇关于记录模块示例代码每次调用重复消息n次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-28 20:58