【问题标题】:Custom Log Levels in python3 is not working?python3中的自定义日志级别不起作用?
【发布时间】:2018-01-09 19:35:18
【问题描述】:

我已经使用 addLevelName() 更改了日志级别的数值,然后将日志放入我的模块中,但在日志文件中,log.error 给我的级别名称为 DEBUG。 这是我尝试的一段代码

class LogAttribute:

def __init__(self):

    logger = logging.getLogger()

    logging.addLevelName(50, "ERROR")
    logging.addLevelName(40, "DEBUG")
    logging.addLevelName(30, "WARNING")
    logging.addLevelName(20, "INFO")
    logging.addLevelName(10, "VERBOSE")

    check = logging.getLevelName(40)
    logger.setLevel(config_obj["loggerLevel"])
    output_dir = (os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    filename = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")+"_EP_script.log"
    handler = logging.FileHandler(os.path.join(output_dir, filename))
    formatter = logging.Formatter(" %(levelname)s - %(message)s")
    handler.setFormatter(formatter)
    logger.addHandler(handler)

【问题讨论】:

  • 我有一个 main.py 文件,它调用不同的模块,并将日志放入其中
  • logging.error("{} - media_data 为空没有要保存的数据".format(name))
  • 此日志给我的输出如下,DEBUG - src.acms.media_list - 提交的 id 200755730 无效
  • 自定义日志级别并非旨在让您重新定位标准现有级别。
  • logging.error() 使用模块级常量logging.ERROR,设置为40

标签: python logging python-3.4


【解决方案1】:

logging 模块未设置为任意重新分配标准日志记录级别。 logging.addLevelName() 方法实际上只是为了添加关卡,而不是用于调整现有关卡。

幕后发生的事情是logging.error() 使用模块级常量logging.ERROR 来记录错误消息。该常量已设置为40,这是您刚刚告诉模块映射到字符串'DEBUG' 的数值。

如果您确实必须重新映射所有级别,则还需要重新分配常量。因为 Python 是一种动态语言,这当然是可能的:

logging.ERROR = 50

但是,我强烈建议您不要这样做。可能有第 3 方框架依赖常量来保持,嗯,常量

如果您正在尝试调整第三方库的日志记录方式,您有更好的选择。每条日志消息都包含一个记录器名称,其中带有. 的名称形成一个层次结构,因此foo.bar.baz 的记录器名称被视为foo.barfoo 的子级,让您通过父节点上的设置来调整子日志节点的日志记录。有关详细信息以及如何配置这些,请参阅Logger objects documentation intro

即使 per-logger-object 和 per-hierarchy 配置选项不适合您的特定用例,您也几乎可以肯定 monkeypatch 这样的模块将 logger 对象替换为基于自定义包装器的在LoggerAdapter pattern。这是因为在第 3 方库中进行日志记录的标准、最佳实践方法是创建一个顶级 logger 对象并将所有日志记录应用到该对象。您可以用包装器替换该对象:

import logging

level_map = {
    logging.ERROR: logging.CRITICAL,
    logging.DEBUG: logging.ERROR
}

class RemappingLogger(logging.LoggerAdapter):
    def __init__(self, logger, extra=None):
        # make the extra parameter optional
        if extra is None:
            extra = {}
        super().__init__(logger, extra)

    def log(self, lvl, *args, **kwargs):
        lvl = level_map.get(lvl, lvl)
        super().log(lvl, *args, **kwargs)


import somelibrary
import somelibrary.submodule

somelibrary.logger = RemappingLogger(somelibrary.logger)
somelibrary.submodule.logger = RemappingLogger(somelibrary.submodule.logger)

您可以使用相同的模式来过滤特定的消息;在这种情况下,提供自定义 LoggingAdapter.process() 方法可能就足够了。

【讨论】:

  • 还有一个问题,每当我将 loggerLevel 设置为 INFO 时,我都有这个日志,INFO - 开始新的 HTTPS 连接 (1):api.airtime.geemedia.com,我真的不感兴趣,我如何禁用它
  • 我不知道。什么图书馆正在记录这个?他们是否使用专用的logging.getLogger() 实例?
  • 请求库正在记录这个,requests.packages.urllib3.connectionpool 这是它来自的文件层次结构
  • @tintin:然后禁用该记录器。为什么要在这里更改关卡?
  • @tintin:我添加了一个更好的选项来处理第 3 方模块中的日志记录配置。与其全局更改关卡的含义,不如根据给定库的具体情况调整关卡。
猜你喜欢
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多