最近在做一个flask的项目,其中需要使用logging模块以来记录日志信息。以下是自己的切身的体会和感悟,希望对读者有所帮助。
1. 基本用法
首先我们来看一下logging的基本语法。
import logging
from logging.handlers import RotatingFileHandler
# 创建一个logger对象,一般web框架本身会有一个,比如flask中的app.logger
logger = logging.getLogger('myapp')
logger.setLevel(20)
# 创建一个handler,这个handler是控制日志的位置以及格式等
handler = RotatingFileHandler('/tmp/logs/2015-06-01.log', maxBytes=5000,backupCount=10)
fmt = logging.Formatter("%(asctime)-15s %(message)s", datefmt='%Y-%m-%d %H:%M:%S')
handler.setFormatter(fmt)
handler.setLevel(10)
# 一个logger可以拥有多个handler,当执行logger.info类似的语句时,会依次调用这个logger的每个handler。
logger.addHandler(handler)
# 在你想加log的地址加入以下语句
logger.info('xxxx')
logger.warning(‘xxxxx')
以下是python中的level常量,通过名字可以知道其所代表的含义。
# python中的level常量:
Level Numeric value
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0
针对上面的基本语法我们依次对其中的知识点做一些讨论。
2. getLogger
函数原型:
logging.getLogger([name])
这个函数就是返回一个logger对象,如果name相同,则会返回同一个对象。
如果name为空,则返回root logger。
注意name的形式必须是a/a.b/a.b.c.d这样的形式,因为logger是按继承层次来区分的。
比如:a.b.c.d的祖先就是a/a.b。a.b的祖先就是a
3. logger的level
level的含义:官方的解释是
Logging messages which are less severe than lvl will be ignored.
比如:
logger.info(‘here’); logger.warning(‘there’)
当logger的level是warning,则只有there会被记录下来。
当logger的level是debug,则here和there都会被记录下来。
需要特别注意的点:
当一个logger被新创建的时候,如果是root logger,则默认level是warning。如果不是root logger,则默认是NOTSET,但是其effective level是按照以下规则得出:
依次往上层寻找,如果直到root logger,一直是NOTSET,则effective level为NOTSET。
如果没到root logger的时候,其某个祖先不是NOTSET,则effective level就是该祖先的level。
4. handler的level
handler也可以设置level。那么handler的level和logger的level有何区别呢?
其实python中的机制是这样的:
当在代码中遇到logger.info/warning这样的语句时:
loglevel赋值于info/warning
然后执行下面语句
if self.level <= loglevel:
for handler in self.handlers:
handler(loglevel, message)
While each of those handlers will then call:
if self.level <= loglevel:
# do something spiffy with the log!
即:首先判断logger的level,如果小于等于loglevel,则会执行其下注册的所有handler。
对于每个handler,只有其level小于等于loglevel才会被记录下来。
参考文章:
https://docs.python.org/2/library/logging.html