2.1简介
Logging库采用模块化方法并且提供了几类组件,它们分别是loggers, handlers, filters, and formatters。
Loggers组件暴露出应用代码能够直接调用的接口。
Handlers组件把日志记录(Logger组件创建的)发给合适的目标。
Filter组件提供一个更优越的方式来决定输出哪个日志记录。
-
Formatters组件指定最终输出的日志记录的格式。
在一个LogRecord实例中,事件日志信息会在loggers,handlers,filters和formatters四个组件中进行传递。
通过调用Logger类实例的方法来执行日志记录(后面统称为loggers)。每个实例都有一个名称,并且它们在概念上以.作为分隔符,排在命名空间层次结构之后。例如,一个名为‘scan’日志记录器是‘scan.text’,‘scan.html’和‘scan.pdf’记录器的父集。Logger的名称可以取你想要的,建议最好是能表明该记录器所记录的区域。
当命名日志器时有一个惯例,就是去使用模块级别的日志器(根据模块命名)。每一个要记录日志的模块都可以按如下进行命名:logger = logging.getLogger(__name__)
这意味着logger的名称是根据所追踪的包/模块进行命名的。这也能够在查询日志信息时很方便的知道是哪个包/模块所记录的日志信息。
顶级层次的日志记录器被称为root logger。这些logger所使用的方法与root logger所调用的方法有着一样的名字,都叫debug(), info(), warning(), error()和critical()。这些功能和方法都具有相同的签名。root logger的名称在输出信息中是“root”。
当然,如果想将日志信息输出到不同的位置,这也很方便。软件包中包含支持用于将日志消息写入文件,HTTP GET / POST位置,通过SMTP发送电子邮件,通用套接字,队列或特定于操作系统的日志记录机制(如syslog或Windows NT事件日志)。目标位置是由handler类来处理的。如果你想一些特殊的需求,内置的handler类也没有提供,那么这时需要你自己创建handler类来处理。
默认情况下是不对任何日志消息设置目标位置的。你可以像基础教程中的那样,通过basicConfig()来设置目标位置(例如控制台或文件)。当你调用debug(),info(),warning(),error()和critical()这些方法时,它们会检测目标位置。如果没有设置,在委托给根记录器来进行实际的消息输出之前,它们会默认输出到控制台(sys.stderr)并且以默认的格式格式化输出信息。
basicConfig()默认的输出信息格式如下:
severity:logger name:message
你可以通过改变basicConfig()的format参数值来调整格式。有关如何构造格式字符串的所有选项,详情见 Formatter Objects。
2.2日志记录流程
在记录事件信息时,loggers与handlers的处理流程如下图所示:

2.2.1.Loggers
Logger对象有3个作用。1.Logger对象对外提供了几个方法,这样应用程序能够在运行时记录消息。2.Logger对象根据消息的严重性(默认的过滤工具)或过滤对象来确定要处理的日志对象。3.Logger对象将相关的日志信息传递给所有感兴趣的日志处理器。
Logger对象使用的最广泛的方法分为两类:配置和发送信息。
以下是最常见的用于配置的方法:
-
Logger.setLevel()指定将要处理的最低严重性的日志消息,注意
debug是严重级别最低的而critical是严重级别最高的。举个例子,如果严重级别设置为INFO,logger对象只会处理INFO,WARNING,ERROR和CRITICAL消息并且会忽略DEBUG消息。 - Logger.addHandler() 和Logger.removeHandler()从logger对象中添加和移除处理对象。
-
Logger.addFilter()和Logger.removeFilter()从logger对象中添加和移除过滤对象。
你不需要每次创建一个Logger对象都调用这些方法。
一旦logger对象配置完成,以下方法就能创建出日志消息: -
Logger.debug(), Logger.info(), Logger.warning(), Logger.error()和Logger.critical()所有这些方法都将创建日志信息以及对应其名字的严重等级。这信息实际上是一个格式化的字符串,这字符串包含了标准的字符串替换语法如
%s,%d,%f等等。这剩下的参数是一个对象列表用于替换日志信息中的占位符。关于参数**kwargs,日志方法只关心exc_info关键字的值,根据这个关键字来决定是否记录异常信息。 - Logger.exception()创建一个类似于Logger.error()方法的日志消息。这两者之间的区别是Logger.exception()会有一个堆栈信息。这个通常是由一个异常处理器进行调用。
-
Logger.log()将日志级别作为一个显示参数。这个方法相比于上面的日志方法要相对冗余,但是可以自定义设置日志级别。
getLogger()方法返回一个logger类实例的引用。通过name参数来指定该logger实例的名称,如果没有指定则命名为root。名字是以句点分隔的层次结构。当多次调用getLogger()方法指定的名称一样时,就会返回同一个对象的引用。在分层列表中较低的logger是列表中较高的logger的子项,举个例子,有一个名为foo的logger,那么名为foo.bar,foo.bar.baz和foo.bam的logger都是foologger的子类。
logger类有一个等效级别的概念。如果logger没有显示设置级别,那么logger会沿用它父级的有效级别。如果父级没找到,会在父级的父级中找,以此类推,直到找到一个有效的级别。根logger的有效级别为WARNING。当执行一个事件时,有效级别就是用于决定需不需要把事件传递给logger的处理器。
子logger会将消息传播给父级相关的处理器。由于这个特性,你不必为一个应用中的所有logger进行定义和配置。只要你为顶级的logger配置处理程序并根据需要创建子logger就足够了。
2.2.2.Handlers
Handler对象的作用是将合适的日志信息(基于日志信息的优先级)转发到handler指定位置。Logger对象能够通过addHandler()方法来添加0个或多个handler对象。有这样一个示例场景,一个应用,需要将所有的日志信息保存到日志文件中,error级别的日志或更高级别的输出到控制台,critical级别的日志需要使用邮件提醒。这个场景需要三个不同的处理器,每个处理器都负责将不同级别的日志信息发送到指定的位置。
标准库中包含了许多处理器的类型(详见Useful Handlers)。在这个教程中主要使用StreamHandler和FileHandler两个处理器。
handler类提供了一些方法供开发者使用。如果开发者准备使用内置的处理器对象,那么以下就是这些配置方法:
- setLevel()用于指定处理器处理的最低级别。logger对象中也有一个setLevel()方法,logger中的是指定哪些信息转发给handle,而这里的指定哪些信息发送到指定位置。
- setFormatter()选择一个formatter对象供handler使用。
- addFilter()和removeFilter()分别是配置filter和移除filter对象。
应用程序代码不应直接实例化和使用Handler类。相反,Handler类是一个基类,它定义了所有处理程序应具有的接口,并建立了子类可以使用的一些默认行为。
2.2.3.Formatters
Formatter对象将会配置日志消息的最终顺序,结构和内容。与logging.Handler基类不同,应用程序代码可以直接实例化formatter类,当然你有一些特殊的要求或行为,你可以编写formatter类的子类。formatter类的构造函数需要三个可选的参数——信息格式字符串,日期格式字符串和样式字符串。
logging.Formatter.init(fmt=None, datefmt=None, style='%')
如果没有设置信息格式字符串,那么会使用默认的信息格式。如果没有设置日期格式字符串,默认的日期格式如下:
%Y-%m-%d %H:%M:%S
最后会加上毫秒数。style参数是%, ‘{’或‘$’中的一个。如果没有指定其中的一个,那么默认将会使用‘%’。如果style参数的值为‘%’,消息格式字符串就会使用%(<dictionary key>)s样式的字符串进行替换。这些可能的键在LogRecord attributes罗列出来了。如果style的值为‘{’,那么消息字符串的格式与str.format()保持一致。如果style的值为‘$’,那么消息格式字符串应该与string.Template.substitute()的格式保持一致。
接下来的信息格式字符串的含义是以可读的时间格式,信息的严重级别和信息内容的顺序进行日志记录:
'%(asctime)s - %(levelname)s - %(message)s'
2.2.4.Configuring Logging
程序配置logging有以下3种方式:
- 明确使用python代码创建loggers对象, handlers对象,和formatters对象并调用上面列出的配置方法进行配置。
- 创建一个日志配置文件并使用fileConfig()方法来读取它。
- 创建一个含有配置信息的字典,再将该字典传递给dictConfig()方法。
有关最后两个选项的参考文档,详见Configuration functions。接下来的例子是使用python代码简单配置一个logger,一个控制台处理器和一个简单的格式化类:
import logging
# create logger
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
logger.critical('critical message')
执行代码,显示如下:
$ python3 simple.py
2018-08-29 10:29:47,835 - simple_example - DEBUG - debug message
2018-08-29 10:29:47,835 - simple_example - INFO - info message
2018-08-29 10:29:47,836 - simple_example - WARNING - warning message
2018-08-29 10:29:47,836 - simple_example - ERROR - error message
2018-08-29 10:29:47,836 - simple_example - CRITICAL - critical message
以下的例子使用配置文件进行配置:
import logging
import logging.config
logging.config.fileConfig('logging.conf')
# create logger
logger = logging.getLogger('simpleExample')
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
以下是logging.conf文件:
[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=
输出如下:
$ python3 simple_file.py
2018-08-29 11:09:08,217 - simpleExample - DEBUG - debug message
2018-08-29 11:09:08,217 - simpleExample - INFO - info message
2018-08-29 11:09:08,218 - simpleExample - WARNING - warning message
2018-08-29 11:09:08,218 - simpleExample - ERROR - error message
2018-08-29 11:09:08,218 - simpleExample - CRITICAL - critical message