0. 前言
1. 组件介绍
- 总体流程如下(非常建议看看):

1.1. Loggers
- Logger的功能:
- 为开发人员提供接口,可以在运行中输出日志。
- 决定产生日志的Level,以及使用的filter。
- 指定日志输出的位置,即指定handler。
- 如果不指定名称,则返回根Logger,默认Level为
warning
。 - Logger存在等级,通过
.
来区分:
- 比如
logging.getLogger('a')
就是loggint.getLogger('a.b')
的父级。 - 存在其他所有Logger的共同祖先——根Logger。
- 如果当前Logger没有指定Level,会默认使用祖先的Level。
- 默认情况下,子类产生的日志(不是全部日志,而是满足子类Level的日志,可以参考之前的总体流程图)会传递给父类的Handler。
- 可以通过设置
propagate
设置,是否使用父类的Handler。
- 多次获取同一个名称的Logger,获取的是同一实例。
- 建议使用的获取Logger的方式是:
logger = logging.getLogger(__name__)
- 其中
__name__
是当前模块的名称(包括package名称)。
- 常用方法:
Logger.setLvel()
Logger.addHandler()
Logger.removeHandler()
Logger.addFilter()
Logger.removeFilter()
Logger.debug()
Logger.exception()
Logger.log(lvl, msg, *args, **kwargs)
1.2. Handlers
- Handler用于指定日志信息的去向。
- 每个Logger可以指定任意数量的Handler(不指定Handler也没关系)。
- Python有很多实现好了的Handler,可以参考这里和这里(推荐)。
class logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)
- 作用:通过文件大小,将日志文件分为多个。
maxBytes
指定文件大小,backupCount
指定最多保存的文件数量。这两个参数都可以设置为0,表示文件大小无限制和文件全部保存。mode
指定打开日志文件的模式。- 文件命名:假设
filename=app.log
,则正在写入的文件名为app.log
,之前保存的日志文件名为app.log.1
,app.log.2
等。
class logging.handlers.TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None)
- 作用:通过时间,分割日志文件。
- 通过
when
和interval
设置时间间隔。 when
取值可以是S, M, H, D
分别表示秒、分、小时、天,之后通过设置interval
来设置时间间隔。when
取值为W0, W1, ..., W6, midnight
,其中W0代表星期一,依次类推。此时表示每周一/…/每周日/每天0点生成新的日志文件。此时interval
没有用处。- 文件命名:可以设置属性
suffix
来确定后缀,添加文件名后。默认suffix
为%Y-%m-%d_%H-%M-%S
。 delay
如果为True
,则日志文件只有在执行过emit()
后才会创建。atTime
可以设置rollover
的启动的时间,需要为datetime.time
实例。
- 一般应用代码不用直接创建Handler对象。
- 常用方法:
setLevel()
setFormatter()
addFilter()
removeFilter()
1.3. Filters
- 用于过滤
LogRecord
。 - 需要定义以下函数,用于创建新的Filter对象。
def should_log(record):
...
return True
logging_filter = logging.Filter()
logging_filter.filter = should_log
1.4. Formatters
- 用于定义日志信息的格式
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
。- 默认值:
fmt=None
等价于'%(message)s'
。datefmt=None
等价于 IOS8601 格式。自己设置等价于time.strftime()
style=None
等价于%
,还可以取值为$
或{
。
- 可用关键字,详细资料参考这里
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(processName)d 进程名称。可能没有
%(message)s 用户输出的消息
2. 配置方法
2.1. 使用Python创建loggers, handlers, filters
import logging
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
2.2. 创建一个配置文件
[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('simpleExample')
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
2.3. 创建一个字典
3. 查漏补缺
3.1. 配置缺失
- 参考:What happens if no configuration is provided
- 对于Python 3.6,如果存在Logger但没有配置相应的Handler,默认会使用
logging.lastResort
,即StreamHandler
。 - 请注意,如果有以下条件。如果子类输出日志信息,会输出到console中。
- 两个logger互为父子关系。
- 父类存在Handler,子类不存在Handler。
- 子类的
propagate
设置为False
。
3.2. 使用Module-Level方法