python logger的继承原理,从根继承的python记录器级别默认情况下设置为警告

In my program I define a logger at the beginning that looks similar to this:

def start_logger():

fh = logging.handlers.RotatingFileHandler('logger.log',

maxBytes=1000000,

backupCount=100)

fh.setLevel(logging.DEBUG)

ch = logging.StreamHandler(sys.stdout)

ch.setLevel(logging.DEBUG)

fh_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'

#fh_fmt = '%(asctime)s - %(funcName)s - %(levelname)s - %(message)s'

ch_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'

#ch_fmt = '%(funcName)s - %(levelname)s - %(message)s'

fh.setFormatter(logging.Formatter(fh_fmt))

ch.setFormatter(logging.Formatter(ch_fmt))

root = logging.getLogger()

root.addHandler(fh)

root.addHandler(ch)

I then have multiple files that are called from my main program. In order for them to work correctly I need to do the following:

import logging

log = logging.getLogger(__name__)

log.setLevel(logging.DEBUG)

log.debug("This debug message is ounly output when I set the level again to debug for this file. Otherwise the the log level for this file is WARNING.")

Why is the default level for all modules that I import set to warning. Why do I have to set the level again to DEBUG for each of them when they import my root logger with log = logging.getLogger(name)? Is this the best way to create a logging module accross a package with different modules or is there a better solution?

解决方案

Let's start by looking at what Handler.setLevel does:

Sets the threshold for this handler to lvl. Logging messages which are less severe than lvl will be ignored. When a handler is created, the level is set to NOTSET (which causes all messages to be processed).

Any messages less severe than lvl are ignored. Effectively, setting it to DEBUG is meaningless (unless you define your own log levels), because there is no less severe message than debug. So, that means that the handler won't ignore any messages.

setLevel is the right idea, but you're calling it on the wrong object. Look at Logger.setLevel:

Sets the threshold for this logger to lvl. Logging messages which are less severe than lvl will be ignored. When a logger is created, the level is set to NOTSET (which causes all messages to be processed when the logger is the root logger, or delegation to the parent when the logger is a non-root logger). Note that the root logger is created with level WARNING.

The term ‘delegation to the parent’ means that if a logger has a level of NOTSET, its chain of ancestor loggers is traversed until either an ancestor with a level other than NOTSET is found, or the root is reached.

If an ancestor is found with a level other than NOTSET, then that ancestor’s level is treated as the effective level of the logger where the ancestor search began, and is used to determine how a logging event is handled.

You're creating the children right, but they're all children of the root logger. They're level is set to NOTSET, and it propagates up to the root, whose default value is WARNING. Consequently, you don't see any messages.

TL;DR:

The solution is simple: set the level on the logger, not the handler. The following code should do what you need:

def start_logger():

fh = logging.handlers.RotatingFileHandler('logger.log',

maxBytes=1000000,

backupCount=100)

ch = logging.StreamHandler(sys.stdout)

fh_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'

#fh_fmt = '%(asctime)s - %(funcName)s - %(levelname)s - %(message)s'

ch_fmt = '%(asctime)s %(levelname)8s %(message)s [%(filename)s:%(lineno)d]'

#ch_fmt = '%(funcName)s - %(levelname)s - %(message)s'

fh.setFormatter(logging.Formatter(fh_fmt))

ch.setFormatter(logging.Formatter(ch_fmt))

logging.basicConfig(level=logging.DEBUG)

root = logging.getLogger()

root.addHandler(fh)

root.addHandler(ch)

Once you do that, you shouldn't need the setLevel call when making the children.

Oh, and to answer your other questions: this is exactly the way you're supposed to use the logging library. (I actually just log everything to the root logger, because I don't need the kind of granularity you developed, but when you have a case for it, you're doing it just as you should.)

EDIT: Evidently, setLevel doesn't seem to work on the root logger. Instead, before accessing the root logger, you have to set basicConfig. Setting the level in logging.basicConfig will do what you need (at least, it worked in my tests). Note, doing this matches the example given in Logging from multiple modules, so should solve your problem.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python logger 是一个内置的日志记录模块,它可以帮助我们在程序中记录和管理日志信息。使用 Python logger,我们可以将程序的运行状态、错误信息等输出到日志文件或者控制台。 要使用 Python logger,我们首先需要导入 logging 模块。然后,我们可以创建一个 logger 对象,并设置它的日志级别、输出格式等属性。接下来,我们可以使用 logger 对象进行日志记录,包括调用不同级别的方法,如 debug、info、warning、error 等。 下面是一个简单的示例: ```python import logging # 创建一个 logger 对象 logger = logging.getLogger('my_logger') # 设置日志级别 logger.setLevel(logging.DEBUG) # 创建一个文件处理器 file_handler = logging.FileHandler('my_log.log') # 设置文件处理器的日志级别 file_handler.setLevel(logging.DEBUG) # 创建一个控制台处理器 console_handler = logging.StreamHandler() # 设置控制台处理器的日志级别 console_handler.setLevel(logging.INFO) # 创建一个日志格式器 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 设置文件处理器和控制台处理器的格式化器 file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 将处理器添加到 logger 对象中 logger.addHandler(file_handler) logger.addHandler(console_handler) # 记录日志 logger.debug('This is a debug message') logger.info('This is an info message') logger.warning('This is a warning message') logger.error('This is an error message') ``` 在上面的示例中,我们创建了一个名为 'my_logger' 的 logger 对象,并设置了它的日志级别为 DEBUG。然后,我们创建了一个文件处理器和一个控制台处理器,并设置它们的日志级别分别为 DEBUG 和 INFO。接着,我们创建了一个日志格式器,并将它设置给文件处理器和控制台处理器。最后,我们使用 logger 对象记录了不同级别的日志信息。 通过使用 Python logger,我们可以更好地跟踪程序的运行状态和调试信息,从而方便地进行错误排查和日志分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值