【问题标题】:Python3 add logging levelPython3 添加日志级别
【发布时间】:2026-01-08 09:50:02
【问题描述】:

我有这段代码,对我来说很好用。

import logging
import logging.handlers

logger = None


def create_logger():
    global logger
    logger = logging.getLogger('Logger')
    logger.setLevel(logging.DEBUG)
    handler = logging.handlers.RotatingFileHandler("C:/Users/user/Desktop/info.log", maxBytes=1000000, backupCount=20)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)


create_logger()
logger.info("Text info")
logger.debug("Text debug")
logger.warning("Text warning")
logger.error("Text error")
logger.critical("Text critical")

而且输出看起来很棒:

2017-12-19 15:06:43,021 - 记录器 - 信息 - 文本信息
2017-12-19 15:06:43,021 - 记录器 - 调试 - 文本调试
2017-12-19 15:06:43,022 - 记录器 - 警告 - 文本警告
2017-12-19 15:06:43,022 - 记录器 - 错误 - 文本错误
2017-12-19 15:06:43,022 - 记录器 - 关键 - 文本关键

好吧,我想像这样添加一个新的日志记录级别:

logger.message("Text message")  

输出应该是这样的

2017-12-19 15:06:43,022 - 记录器 - 消息 - 短信

谢谢

【问题讨论】:

  • “消息”与“信息”或任何其他级别有何不同?

标签: python logging python-3.5


【解决方案1】:

来自Logging documentation(已添加重点):

定义您自己的级别是可能的,但不是必须的,因为 现有水平是根据实际情况选择的 经验。但是,如果您确信需要自定义关卡, 执行此操作时应格外小心,这可能是 如果您正在开发库,那么定义自定义级别是非常糟糕的主意。 那是因为如果多个库作者都定义了自己的自定义 级别,有可能从这样的多个日志输出 一起使用的库对于使用开发人员来说将很难 控制和/或解释,因为给定的数值可能意味着 不同的图书馆有不同的东西。

默认logging levels概览:

但如果你还想,你可以自己做日志级别:

logging 模块中,_levelToName_nameToLevel 是日志名称和级别之间的映射。 addLevelName() 函数会为您完成此操作,而不是手动添加。

这里,添加了一个名为 MESSAGE 的新日志级别,日志级别为 25

import logging

# Define MESSAGE log level
MESSAGE = 25

# "Register" new loggin level
logging.addLevelName(MESSAGE, 'MESSAGE')  # addLevelName(25, 'MESSAGE')

# Verify
assert logging.getLevelName(MESSAGE) == 'MESSAGE'

如果您不想制作自己的 logger 类但仍想记录其他日志级别,则可以在传统 loggers 上使用Logger.log(level, msg)-方法:

logging.log(MESSAGE, 'This is a message')

编辑:直接添加消息

 def message(self, msg, *args, **kwargs):
    if self.isEnabledFor(MESSAGE):
        self._log(MESSAGE, msg, args, **kwargs) 

使message() 函数在logging 中可用:

 logging.message = message
 # or setattr(logging, 'message', message)

使message()-函数在记录器中可用:

 logging.Logger.message = message
 # or setattr(logging.Logger, 'message', message)

制作自定义 Logger 类

您可以创建自己的记录器类来创建 message(msg) 方法,以与其他方法类似地使用(例如 info(msg)warning(msg) 等)

在以下示例中,使用message(msg)-方法创建了一个新记录器来记录MESSAGE

class MyLogger(logging.Logger):
    def message(self, msg, *args, **kwargs):
        if self.isEnabledFor(MESSAGE):
            self._log(MESSAGE, msg, args, **kwargs)

获取记录器

我不确定使用logging.getLogger(name) 的最佳方法是什么,但以下是两种方法。 参考。 cmets,我相信第一种方法更好:

要么将新记录器设为默认记录类,这意味着新记录器实例将属于MyLogger 类,而不是默认的logging.Logger 类:

logging.setLoggerClass(MyLogger)
logger = logging.getLogger('A new logger name')
logger.message('This seems to work')
assert isInstance(logger, MyLogger)

或者只需创建一个记录器实例并将其添加到活动logging.Manager 实例中的loggerDict编辑:不推荐,请参阅 cmets):

my_logger = MyLogger('Foo')
logging.Logger.manager.loggerDict['Foo'] = my_logger
logger = logging.getLogger('Foo')
logger.message('This is the same instance as my_logger')
assert logger is my_logger

使用新的日志级别

# Use the new logger class
logger.warning('Custom log levels might be a bad idea')
logger.message('Here is a message')
# Log with custom log level:
logger.log(MESSAGE, 'This is a message')

这假定MESSAGE 被预定义为一个表示日志级别的整数数值。 (例如前面提到的 25

【讨论】:

  • 一般来说你的答案是好的,但你建议的一些事情涉及使用日志内部,这可能不是一个好主意。比如直接实例化一个logger实例(MyLogger),或者手动更新manager的loggerDict
  • 感谢您的反馈。为了解决您的评论,我已经更新了我的答案,但我希望有任何额外的反馈。
  • 很好的解释!涵盖了我一直在寻找的一切。加一个。