我正在为一个依赖于第三方软件的项目实现python.logging,该软件也使用日志(log)记录.

问题是我们想要控制台输出,而来自两者的日志(log)是双重打印的.有没有办法设置一个处理程序来"组合"子处理程序的输出?

import logging
import sys


def third_party_use():
    print_log = logging.StreamHandler(stream=sys.stdout)
    print_log.setLevel(logging.INFO)
    print_log.name = "SubPrintLog"
    print_log.setFormatter(logging.Formatter("SubPrintLog %(name)s - %(levelname)s: %(message)s"))

    third_party_logger = logging.getLogger("ThirdParty")
    third_party_logger.addHandler(print_log)
    third_party_logger.info("I don't want this to print twice")


if __name__ == '__main__':
    print_log = logging.StreamHandler(stream=sys.stdout)
    print_log.setLevel(logging.INFO)
    print_log.name = "MyPrintLog"
    print_log.setFormatter(logging.Formatter("MyPrintLog %(name)s - %(levelname)s: %(message)s"))

    logging.basicConfig(level=0, handlers=[print_log])
    logger = logging.getLogger(__name__)

    logger.debug("This shouldn't appear")
    logger.info("This should")
    logger.warning("This definitely should")

    third_party_use()

    logger.info("Just my stuff again")

yield 率:

MyPrintLog __main__ - INFO: This should
MyPrintLog __main__ - WARNING: This definitely should
SubPrintLog ThirdParty - INFO: I don't want this to print twice
MyPrintLog ThirdParty - INFO: I don't want this to print twice
MyPrintLog __main__ - INFO: Just my stuff again

有没有办法将MyPrintLog设置为不复制ThirdParty的输出(假设我们无权修改ThirdParty的配置).我希望propagate旗帜可以解决这个问题,但它向相反的方向流动,我们无法修改ThirdParty)

一种"有效"的解决方案是在拨打ThirdParty时有效地禁用MyPrintLog:

def turn_off_console():
    for idx, handler in enumerate(logger.root.handlers):
        if handler.name == "MyPrintLog":
            old_level = handler.level
            handler.setLevel(logging.CRITICAL)
            return idx, old_level


def turn_on_console(handle_index, level):
    logger.root.handlers[handle_index].setLevel(level)

然后将每个访问都包装到第三方:

    idx, old_level = turn_off_console()
    third_party_use()
    turn_on_console(idx, old_level)

这将产生正确的输出:

MyPrintLog __main__ - INFO: This should
MyPrintLog __main__ - WARNING: This definitely should
SubPrintLog ThirdParty - INFO: I don't want this to print twice
MyPrintLog __main__ - INFO: Just my stuff again

但是,这意味着我每次都必须切换记录器,这很容易出错.

编辑:已解决

class NoThirdParty(logging.Filter):
    def filter(self, record):
        return not record.name == "ThirdParty"

if __name__ == '__main__':
    print_log = logging.StreamHandler(stream=sys.stdout)
    print_log.setLevel(logging.INFO)
    print_log.addFilter(NoThirdParty()) # Do Not Reproduce Third Party!
    print_log.name = "MyPrintLog"
    print_log.setFormatter(logging.Formatter("MyPrintLog %(name)s - %(levelname)s: %(message)s"))
    
    ...

yield 率:

MyPrintLog __main__ - INFO: This should
MyPrintLog __main__ - WARNING: This definitely should
SubPrintLog ThirdParty - INFO: I don't want this to print twice
MyPrintLog __main__ - INFO: Just my stuff again

This Solution通过将过滤器应用到第三方记录器解决了同样的问题

推荐答案

class NoThirdParty(logging.Filter):
    def filter(self, record):
        return not record.name == "ThirdParty"

if __name__ == '__main__':
    print_log = logging.StreamHandler(stream=sys.stdout)
    print_log.setLevel(logging.INFO)
    print_log.addFilter(NoThirdParty()) # Do Not Reproduce Third Party!
    print_log.name = "MyPrintLog"
    print_log.setFormatter(logging.Formatter("MyPrintLog %(name)s - %(levelname)s: %(message)s"))
    
    ...

yield 率:

MyPrintLog __main__ - INFO: This should
MyPrintLog __main__ - WARNING: This definitely should
SubPrintLog ThirdParty - INFO: I don't want this to print twice
MyPrintLog __main__ - INFO: Just my stuff again

Python相关问答推荐

单击Cookie横幅错误并在Selenium中启用搜索栏

如何从维基百科的摘要部分/链接列表中抓取链接?

键盘.任务组

pyramid 内部数组中的连续序列-两极

Python无法在已导入的目录中看到新模块

如何让我的Tkinter应用程序适合整个窗口,无论大小如何?

如何使用stride_tricks.as_strided逆转NumPy数组

使用Keras的线性回归参数估计

将特定列信息移动到当前行下的新行

运行总计基于多列pandas的分组和总和

. str.替换pandas.series的方法未按预期工作

如何获取TFIDF Transformer中的值?

为什么默认情况下所有Python类都是可调用的?

Telethon加入私有频道

如何在Python脚本中附加一个Google tab(已经打开)

无法使用DBFS File API路径附加到CSV In Datricks(OSError Errno 95操作不支持)

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

与命令行相比,相同的Python代码在Companyter Notebook中运行速度慢20倍

如何在PySide/Qt QColumbnView中删除列

Geopandas未返回正确的缓冲区(单位:米)