📦 归档笔记 — 原创建于 WizNote,仅作归档展示;观点以当年为准,非最新。

python logging配置和使用

创建时间2021-04-14最后修改2021-04-14原位置/程序员成长之旅/Python学习/字数4707
目录:程序员成长之旅/Python学习

日志库

日志事件

日志事件信息在 LogRecord 实例中的记录器、处理程序、过滤器和格式化程序之间传递。

记录器命名


logger = logging.getLogger(__name__)

(*)重要使用说明!!!

  1. 先在主模块定义logger'mainModule',进行配置,后可在解释器进程里其他地方通过getLogger( 'mainModule')得到一样的对象,不需重新配置,可直接使用。

  2. **(*)**定义该logger子logger,都可共享父logger定义和配置,所谓父子logger是通过命名来识别,任意以 'mainModule'开头logger都是它的子logger,例如'mainModule.sub'

  3. 实际开发一个application,先通过logging配置文件编application配置,可生成一个根logger,如'PythonAPP',然后在主函数中通过fileConfig()加载logging配置,接着在application的其他地方、不同的模块中,可用根logger的子logger,如'PythonAPP.Core''PythonAPP.Web'来进行log,而不需反复的定义和配置各个模块的logger。

消息可以记录在不同的地方

  1. 写入文件

  2. HTTP GET/POST 位置

  3. 通过 SMTP 发送电子邮件

  4. 通用套接字

  5. 队列或特定于操作系统的日志记录机制(如 syslog 或 Windows NT 事件日志)

日志库组件

  1. 记录器: 记录器暴露了应用程序代码直接使用的接口。

  2. 处理程序: 处理程序将日志记录(由记录器创建)发送到适当的目标。

  3. 过滤器: 过滤器提供了更精细的附加功能,用于确定要输出的日志记录。

  4. 格式化程序: 格式化程序指定最终输出中日志记录的样式。

记录器

记录器介绍

Logger 对象有三重任务。首先,它们向应用程序代码公开了几种方法,以便应用程序可以在运行时记录消息。其次,记录器对象根据严重性(默认过滤工具)或过滤器对象确定要处理的日志消息。第三,记录器对象将相关的日志消息传递给所有感兴趣的日志处理程序。

记录器对象上使用最广泛的方法分为两类:配置和消息发送。

常见配置方法

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

2.  和 Logger.removeHandler() 从记录器对象中添加和删除处理程序对象。处理程序在以下内容中有更详细的介绍 处理程序

  1. Logger.addFilter()Logger.removeFilter() 可以添加或移除记录器对象中的过滤器。 Filter 对象 包含更多的过滤器细节。

不需要始终创建的每个记录器上调用这些方法。

配置完成后的应用

1.  Logger.info()Logger.warning()Logger.error()Logger.critical() 都创建日志记录,包含消息和与其各自方法名称对应的级别。该消息实际上是一个格式化字符串,它可能包含标题字符串替换语法 %s%d%f 等等。其余参数是与消息中的替换字段对应的对象列表。关于 **kwargs ,日志记录方法只关注 exc_info 的关键字,并用它来确定是否记录异常信息。

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

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

getLogger()

返回返回对具有指定名称的记录器实例的引用(如果已提供),或者如果没有则返回 root 。名称是以句点分隔的层次结构。多次调用 getLogger() 具有相同的名称将返回对同一记录器对象的引用。在分层列表中较低的记录器是列表中较高的记录器的子项。例如,给定一个名为 foo 的记录器,名称为 foo.barfoo.bar.bazfoo.bam 的记录器都是 foo 子项。

有效等级记录器具有 有效等级 的概念。如果未在记录器上显式设置级别,则使用其父级别作为其有效级别。如果父级没有明确的级别设置,则检查 父级。依此类推,搜索所有上级元素,直到找到明确设置的级别。根记录器始终具有显式级别集(默认情况下为 WARNING )。在决定是否处理事件时,记录器的有效级别用于确定事件是否传递给记录器的处理程序。

子记录器传播到上级记录器的处理程序子记录器将消息传播到与其上级记录器关联的处理程序。因此,不必为应用程序使用的所有记录器定义和配置处理程序。为顶级记录器配置处理程序并根据需要创建子记录器就足够了。(但是,你可以通过将记录器的 propagate 属性设置 False 来关闭传播。)

处理程序

处理程序介绍

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

处理程序存在多个

标准库包含很多处理程序类型(参见 有用的处理程序 );教程主要使用 StreamHandlerFileHandler

方法很少直接暴露给开发者

处理程序中很少有方法可供应用程序开发人员使用。

开发者一般使用内置处理程序对象

与使用内置处理程序对象(即不创建自定义处理程序)的应用程序开发人员相关的唯一处理程序方法是以下配置方法:

  1. setLevel() 方法,就像在记录器对象中一样,指定将被分派到适当目标的最低严重性。为什么有两个 setLevel() 方法?记录器中设置的级别确定将传递给其处理程序的消息的严重性。每个处理程序中设置的级别确定处理程序将发送哪些消息。

  2. setFormatter() 选择一个该处理程序使用的 Formatter 对象。

  3. addFilter()removeFilter() 分别在处理程序上配置和取消配置过滤器对象。

应用程序代码不应该直接实例化并使用Handler实例

应用程序代码不应直接实例化并使用 Handler 的实例。 相反, Handler 类是一个基类,它定义了所有处理程序应该具有的接口,并建立了子类可以使用(或覆盖)的一些默认行为。

(*)有用的处理程序
  1. StreamHandler 实例发送消息到流(类似文件对象)。

  2. FileHandler 实例将消息发送到硬盘文件。

  3. BaseRotatingHandler 是轮换日志文件的处理程序的基类。它并不应该直接实例化。而应该使用 RotatingFileHandlerTimedRotatingFileHandler 代替它。

  4. RotatingFileHandler 实例将消息发送到硬盘文件,支持最大日志文件大小和日志文件轮换。

  5. TimedRotatingFileHandler 实例将消息发送到硬盘文件,以特定的时间间隔轮换日志文件。

  6. SocketHandler 实例将消息发送到 TCP/IP 套接字。从 3.4 开始,也支持 Unix 域套接字。

  7. DatagramHandler 实例将消息发送到 UDP 套接字。从 3.4 开始,也支持 Unix 域套接字。

  8. SMTPHandler 实例将消息发送到指定的电子邮件地址。

  9. SysLogHandler 实例将消息发送到 Unix syslog 守护程序,可能在远程计算机上。

  10. NTEventLogHandler 实例将消息发送到 Windows NT/2000/XP 事件日志。

  11. MemoryHandler 实例将消息发送到内存中的缓冲区,只要满足特定条件,缓冲区就会刷新。

  12. HTTPHandler 实例使用 GETPOST 方法将消息发送到 HTTP 服务器。

  13. WatchedFileHandler 实例会监视他们要写入日志的文件。如果文件发生更改,则会关闭该文件并使用文件名重新打开。此处理程序仅在类 Unix 系统上有用; Windows 不支持依赖的基础机制。

  14. QueueHandler 实例将消息发送到队列,例如在 queuemultiprocessing 模块中实现的队列。

  15. NullHandler 实例对错误消息不执行任何操作。它们由想要使用日志记录的库开发人员使用,但是想要避免如果库用户没有配置日志记录,则显示 "无法找到记录器XXX的消息处理器" 消息的情况。有关更多信息,请参阅 配置库的日志记录

格式化程序

格式化程序介绍

格式化程序对象配置日志消息的最终顺序、结构和内容。 与 logging.Handler 类不同,应用程序代码可以实例化格式化程序类,但如果应用程序需要特殊行为,则可能会对格式化程序进行子类化。

构造器函数参数

构造函数有三个可选参数 —— 消息格式字符串、日期格式字符串和样式指示符。


logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
默认格式

默认行为: 使用原始信息

日期格式字符串默认行为: %Y-%m-%d %H:%M:%S

style: 是{ $ 之一。 如果未指定其中一个,则将使用

格式示例

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

实践配置日志

配置日志的三种方法

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

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

  3. 使用字典来保存配置信息

  4. 在 Python 3.2 中,引入了一种新的配置日志记录的方法,使用字典来保存配置信息。 这提供了上述基于配置文件方法的功能的超集,并且是新应用程序和部署的推荐配置方法。

  5. 示例代码

  6. 
    

version: 1

formatters:

simple:

format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

handlers:

console:

class: logging.StreamHandler

level: DEBUG

formatter: simple

stream: ext://sys.stdout

loggers:

simpleExample:

level: DEBUG

handlers: [console]

propagate: no

root:

level: DEBUG

handlers: [console]


3. 创建配置信息字典并将其传递给 [`dictConfig()`](https://docs.python.org/zh-cn/3/library/logging.config.html#logging.config.dictConfig) 函数。

(*)第2和3中方法详见[配置函数](https://docs.python.org/zh-cn/3/library/logging.config.html#logging-config-api)

#### 例子

#### 例1

```python

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('warn message')

logger.error('error message')

logger.critical('critical message')

从命令行运行此模块将生成以下输出:


$ python simple_logging_module.py

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

例1.2


#文件: 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=

#文件: logging.conf

#(使用新方法进行配置)

version: 1

formatters:

simple:

format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

handlers:

console:

class: logging.StreamHandler

level: DEBUG

formatter: simple

stream: ext://sys.stdout

loggers:

simpleExample:

level: DEBUG

handlers: [console]

propagate: no

root:

level: DEBUG

handlers: [console]

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')

$ python simple_logging_config.py

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

警告:fileConfig()接受一个默认参数disable_existing_loggers, 默认值为True

如果没有提供配置文件
发生的行为取决于Python版本

如果未提供日志记录配置,则可能出现需要输出日志记录事件但无法找到输出事件的处理程序的情况。 在这些情况下,日志包的行为取决于 Python 版本。

对于3.2之前的Python版本,行为如下:

  • 如果 logging.raiseExceptionsFalse (生产模式),则会以静默方式丢弃该事件。

  • 如果 logging.raiseExceptionsTrue (开发模式),则会打印一条消息“无法找到记录器 X.Y.Z 的处理程序”。

在 Python 3.2 及更高版本中,行为如下:

  • 事件使用“最后的处理程序”输出,存储在 logging.lastResort 中。 这个内部处理程序与任何记录器都没有关联,它的作用类似于 StreamHandler ,它将事件描述消息写入 sys.stderr 的当前值(因此服从任何可能的重定向影响)。 没有对消息进行格式化——只打印裸事件描述消息。处理程序的级别设置为“警告”,因此将输出此级别和更高级别的所有事件。

要获得 3.2 之前的行为, logging.lastResort 可以设置为 None

配置库的日志记录

什么都不做的处理程序
NullHandler

日志包中包含一个不做任何事情的处理程序: NullHandler (自 Python 3.1 起)。可以将此处理程序的实例添加到库使用的日志记录命名空间的顶级记录器中( 如果 你希望在没有日志记录配置的情况下阻止库的记录事件输出到 sys.stderr )。如果库 foo 的所有日志记录都是使用名称匹配 'foo.x' , 'foo.x.y' 等的记录器完成的,那么代码:


logging.getLogger('foo').addHandler(logging.NullHandler())

注解: 强烈建议你 不要将 NullHandler 以外的任何处理程序添加到库的记录器中 。这是因为处理程序的配置是使用你的库的应用程序开发人员的权利。应用程序开发人员了解他们的目标受众以及哪些处理程序最适合他们的应用程序:如果你在“底层”添加处理程序,则可能会干扰他们执行单元测试和提供符合其要求的日志的能力。

日志级别

(*)也可以自己定义级别

标准日志级别

| 级别       | 数值 |

| :--------- | ---- |

| CUITICAL | 50   |

| ERROR    | 40   |

| WARNING  | 30   |

| INFO     | 20   |

| DEBUG    | 10   |

| NOTSET   | 0    |

自定义级别

定义你自己的级别是可能的,但不一定是必要的,因为现有级别是根据实践经验选择的。但是,如果你确信需要自定义级别,那么在执行此操作时应特别小心,如果你正在开发库,则 定义自定义级别可能是一个非常糟糕的主意 。 这是因为如果多个库作者都定义了他们自己的自定义级别,那么使用开发人员很难控制和解释这些多个库的日志记录输出,因为给定的数值可能意味着不同的东西 对于不同的库。