python学习系列之logging(二、进阶教程)


按照官方使用说明进行编写

1. logging进阶教程

在官方文档的logging模块中,主要包含5个类:

  1. logging.Logger
  2. logging.Handler
  3. logging.Formatter
  4. logging.Filter
  5. logging.LogRecord

详情如下表:

组件名称对应类名功能描述
日志器Logger提供了应用程序直接使用的接口
处理器Handler将logger创建的日志记录发送到合适的目的输出
过滤器Filter提供了更精细的附加功能来决定输出哪条日志记录,丢弃哪条日志记录
格式器Formatter决定日志记录的最终输出格式
日志记录器LogRecord在记录日志时Logger会自动创建LogRecord实例

日志事件信息在 LogRecord 实例中的记录器、处理器、过滤器和格式器之间传递。
通过调用 Logger 类(以下称为 loggers , 日志器)的实例来执行日志记录。 每个实例都有一个名称,它们在概念上以点(句点)作为分隔符排列在命名空间的层次结构中。 例如,名为 ‘scan’ 的记录器是记录器 ‘scan.text’ ,‘scan.html’ 和 ‘scan.pdf’ 的父级。 记录器名称可以是你想要的任何名称,并指示记录消息源自的应用程序区域。

命名记录器时使用的一个好习惯是在每个使用日志记录的模块中使用模块级记录器,命名如下:

logger = logging.getLogger(__name__)
# 这意味着记录器名称跟踪包或模块的层次结构,并且直观地从记录器名称显示记录事件的位置。

记录器层次结构的根称为根记录器。 这是函数 debug() 、 info() 、 warning() 、 error() 和 critical() 使用的记录器,它们只调用根记录器的同名方法。 功能和方法具有相同的签名。 根记录器的名称在记录的输出中打印为 ‘root’ 。

logging模块支持将日志输出到如下这些地方:

序号位置
1写入文件
2HTTP GET/POST
3通过SMTP发送email
4通用套接字(generic sockets)
5队列
5特定于操作系统的日志记录机制(如 syslog 或 Windows NT 事件日志)

通过 handler 类可以指明日志到底输出到哪里。而且可以根据需要创建自己的日志输出类。

默认情况下,没有为任何日志记录消息设置日志输出目的地。 你可以使用 basicConfig() 指定目标(例如控制台或文件),如教程示例中所示。 如果你调用函数 debug() 、 info() 、 warning() 、 error() 和 critical() ,他们将检查是否有设置日志输出目的地;如果没有设置,它们将在委托给根记录器进行实际的消息输出之前设置目标为控制台( sys.stderr )和默认格式的显示消息。

由 basicConfig() 设置的消息默认格式为:

severity:logger name:message

记录器和处理程序中的日志事件信息流程如下图所示。
日志处理流程

2. Logger

logger中常见的配置方法是:

Logger.setLevel() 指定日志记录器将处理的最低严重性日志消息,其中 debug 是最低内置严重性级别, critical 是最高内置严重性级别。 例如,如果严重性级别为 INFO ,则记录器将仅处理 INFO 、 WARNING 、 ERROR 和 CRITICAL 消息,并将忽略 DEBUG 消息。

Logger.addHandler() 和 Logger.removeHandler() 从日志记录器对象中添加和删除处理程序对象。处理程序在以下内容中有更详细的介绍 处理程序 。例如,在使用flask中的logging时就可能会同时使用到这两个方法。

Logger.addFilter() 和 Logger.removeFilter() 可以添加或移除日志记录器对象中的过滤器。

当Logger(日志记录器)配置好之后,可以通过Logger.debug() 、 Logger.info() 、 Logger.warning() 、 Logger.error() 和 Logger.critical() 来创建日志记录,不同的方法名称对应的级别。

Logger.exception() 创建与 Logger.error() 相似的日志信息。 不同之处是, Logger.exception() 同时还记录当前的堆栈追踪。仅从异常处理程序调用此方法。

Logger.log() 将日志级别作为显式参数。对于记录消息而言,这比使用上面列出的日志级别方便方法更加冗长,但这是自定义日志级别的方法。

2.1 关于getLogger()方法

getLogger() 返回的是具有指定名称的日志记录器实例的一个引用(如果已创建),没有则返回 root (根日志记录器)。名称是以句点分隔的层次结构。多次调用 getLogger() 具有相同的名称将返回对同一记录器对象的引用。在分层列表中较低的日志记录器是列表中较高的记录器的子项。例如,给定一个名为 foo 的日志记录器,名称为 foo.bar 、 foo.bar.baz 和 foo.bam 的记录器都是 foo 子项。
日志记录器具有 有效等级的概念。如果未在日志记录器上显式设置级别,则使用其父级别作为其有效级别。如果父级没有明确的级别设置,则检查父的父级。依此类推,搜索所有上级元素,直到找到明确设置的级别。根记录器始终具有显式级别集(默认情况下为 WARNING )。在决定是否处理事件时,日志记录器的有效级别用于确定事件是否传递给日志记录器的处理程序或者直接忽略。
子记录器将消息传播到与其上级记录器关联的处理程序。因此,不必为应用程序使用的所有记录器定义和配置处理程序。为顶级记录器配置处理程序并根据需要创建子记录器就足够了。(但是,你可以通过将记录器的 propagate 属性设置 False 来关闭传播。)例如,配置好了父日志记录器写入文件test.log中,这时若子记录器的propagate属性为True,那么么子记录器中产生的日志也会输出到父日志记录的的输出位置,也就是文件test.log中。

3. Handler

Handler 对象负责将适当的日志消息(基于日志消息的严重性)分派给处理器的指定输出目标。 Logger 对象可以使用 addHandler() 方法向自己添加零个或多个处理器对象。作为示例场景,应用程序可能希望将所有日志消息发送到日志文件,将错误或更高的所有日志消息发送到标准输出(例如控制台),以及将所有关键消息发送至一个邮件地址。 此方案需要三个单独的处理器,其中每个处理器负责将特定严重性的消息发送到特定位置。

处理器类别如下:

handler子类描述
StreamHandler实例发送消息到流(类似文件对象)。
FileHandler实例将消息发送到硬盘文件。
BaseRotatingHandler是轮换日志文件的处理程序的基类。它并不应该直接实例化。而应该使用 RotatingFileHandler 或 TimedRotatingFileHandler 代替它。
RotatingFileHandler实例将消息发送到硬盘文件,支持最大日志文件大小和日志文件轮换。
TimedRotatingFileHandler实例将消息发送到硬盘文件,以特定的时间间隔轮换日志文件。
SocketHandler实例将消息发送到 TCP/IP 套接字。从 3.4 开始,也支持 Unix 域套接字。
DatagramHandler实例将消息发送到 UDP 套接字。从 3.4 开始,也支持 Unix 域套接字。
SMTPHandler实例将消息发送到指定的电子邮件地址。
SysLogHandler实例将消息发送到 Unix syslog 守护程序,可能在远程计算机上。
NTEventLogHandler实例将消息发送到 Windows NT/2000/XP 事件日志。
MemoryHandler实例将消息发送到内存中的缓冲区,只要满足特定条件,缓冲区就会刷新。
HTTPHandler实例使用 GET 或 POST 方法将消息发送到 HTTP 服务器。
WatchedFileHandler实例会监视他们要写入日志的文件。如果文件发生更改,则会关闭该文件并使用文件名重新打开。此处理程序仅在类 Unix 系统上有用; Windows 不支持依赖的基础机制。
QueueHandler实例将消息发送到队列,例如在 queue 或 multiprocessing 模块中实现的队列。
NullHandler实例对错误消息不执行任何操作。它们由想要使用日志记录的库开发人员使用,但是想要避免如果库用户没有配置日志记录,则显示 "无

经常使用的也就是StreamHandler、FileHandler、RotatingFileHandler、TimedRotatingFileHandler。
日志记录器主要使用的配置方法如下:

setLevel() 方法,就像在记录器对象中一样,指定将被分派到适当目标的最低严重性。为什么有两个 setLevel() 方法?记录器中设置的级别确定将传递给其处理器的消息的严重性。每个处理器中设置的级别确定处理器将发送哪些消息。
setFormatter() 选择一个该处理器皿使用的 Formatter 对象。决定了日志输出的格式。
addFilter() 和 removeFilter() 分别在处理器上配置和取消配置过滤器对象。决定输出哪些日志。

注意:应用程序代码不应直接实例化并使用 Handler 的实例。 因为, Handler 类是一个基类,它定义了所有处理程序应该具有的接口,并建立了子类可以使用(或覆盖)的一些默认行为。所以用上面的那些handler子类来创建处理器实例是更好的选择。

4. Formatter

格式器对象配置日志消息的最终顺序、结构和内容。 与 logging.Handler 类不同,应用程序代码可以实例化格式器类,但如果应用程序需要特殊行为,则可能会对格式器进行子类化。构造函数有三个可选参数 —— fmt(消息格式字符串)、datefmt(日期格式字符串)和style(样式指示符)。

如果没有消息格式字符串,则默认使用原始消息。如果没有日期格式字符串,则默认日期格式为:

%Y-%m-%d %H:%M:%S

以下消息格式字符串将以人类可读的格式记录时间、消息的严重性以及消息的内容,按此顺序:

'%(asctime)s - %(levelname)s - %(message)s'

格式化程序使用用户可配置的函数将记录的创建时间转换为元组。 默认情况下,使用 time.localtime() ;要为特定格式化程序实例更改此项,请将实例的 converter 属性设置为具有相同签名的函数 time.localtime() 或 time.gmtime() 。 要为所有格式化程序更改它,例如,如果你希望所有记录时间都以 GMT 显示,请在格式化程序类中设置 converter 属性(对于 GMT 显示,设置为 time.gmtime )。

5. 配置日志记录

开发者可以通过三种方式配置日志记录:

  1. 使用调用上面列出的配置方法的 Python 代码显式创建记录器、处理程序和格式化程序。

  2. 创建日志配置文件并使用 fileConfig() 函数读取它。

  3. 创建配置信息字典并将其传递给 dictConfig() 函数。

5.1 配置方法创建日志

有关最后两个选项的参考文档,请参阅 Configuration functions 。 以下示例使用 Python 代码配置一个非常简单的记录器/一个控制台处理程序和一个简单的格式化程序:

import logging

# 创建一个logger,名称为'simple_example'
logger = logging.getLogger('simple_example')
# 设置其最低级别是logging.DEBUG
logger.setLevel(logging.DEBUG)

# 创建一个控制台handler,其最低级别是logging.DEBUG
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

# 创建一个格式器,决定日志的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 为handler添加一个格式器
ch.setFormatter(formatter)

# 为logger添加handler
logger.addHandler(ch)

# 在应用中通过下列方法输出日志。
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')


# 控制台的输出如下
2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
2005-03-19 15:10:26,620 - simple_example - INFO - info message
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
2005-03-19 15:10:26,697 - simple_example - ERROR - error message
2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message

5.2

以下 Python 模块创建的记录器、处理程序和格式化程序几乎与上面列出的示例中的相同,唯一的区别是对象的名称:

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.warning('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=

输出如下:

2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
2005-03-19 15:38:55,979 - simpleExample - INFO - info message
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message

参考文献

[1] 官方使用说明-教程
[2] 官方文档-日志操作手册
[3] Python日志库logging总结-可能是目前为止将logging库总结的最好的一篇文章
[4] Python之路(第十七篇)logging模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值