【Python】基础学习&技能提升&代码样例6:日志logging

logging 模块实现了python的日志能力。本文通过几个示例展示一些重点概念与用法。

一、线程安全介绍

logging 模块的目标是使客户端不必执行任何特殊操作即可确保线程安全。 它通过使用线程锁来达成这个目标;用一个锁来序列化对模块共享数据的访问,并且每个处理程序也会创建一个锁来序列化对其下层 I/O 的访问。

如果你要使用 signal 模块来实现异步信号处理程序,则可能无法在这些处理程序中使用 logging。 这是因为 threading 模块中的锁实现并非总是可重入的,所以无法从此类信号处理程序发起调用。

二、快速使用

2.1 基本流程

python的日志功能由以下三个模块(module)构成(在import的时候,会碰到导入这三个模块):

  • logging:模块提供主要的面向客户端的API。
  • logging.config:模块提供API来配置客户端中的日志记录。
  • logging.handlers:模块提供不同的处理程序,涵盖常见的处理方式并分发日志记录。

具体的,主要由下面5个类构成:
Logger:日志器,暴露函数给应用程序,基于日志记录器和过滤器级别决定哪些日志有效。
LogRecord:日志记录器,将日志传到相应的处理器处理。
Handler:处理器,将(日志记录器产生的)日志记录发送至合适的目的地。
Filter:过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记录。
Formatter:格式化器,指明了最终输出中日志记录的布局。

其中Logger日志器是分层级的,根部的为根日志器,子日志器会向上调用父日志器的handle(参数propagate确定,该参数默认为True):
在这里插入图片描述
注意: 博主根据经验推测:A、B和root之间仅是拷贝了root的handler配置,不存在propagate为True时的调用关系,所以用虚线表示(见示例2)

具体流程图如下:
logger为上图中的某一级创建的一个实例,可以是loggerlogger1logger2,为了方便,都写成了logger
在这里插入图片描述
看图即可理解流程,这里不赘述。
注意

  • logger.propagate=true时不是调用父记录器Logger,只调用其处理程序(handlers)。这意味着记录器类中的过滤器和其他代码不会在父级上执行。这是向记录器添加过滤器时的常见陷阱。
  • 可以看到,过滤器有两个,一个值在Logger中,一个是在Handler中,在设置时一定要注意。
  • 参数propagate默认为True,所以父日志器的handler默认全部调用,这也就是为什么通常子日志器能调用根日志器handler输出的愿意。(注意,验证中发现一个例外的点:如果子日志器配置了hanlder,而根日志器的默认handler不做处理,则根日志器的默认handler不再调用,见示例2)
  • 一个日志器可配置多个handler,不同的handler可以配置不同的输出源,比如h1输出到文件,h2通过http输出到某个发送短信的服务提醒运维。

日志级别:

级别 数值 何种含义 / 何时使用
logging.NOTSET 0 当在日志记录器上设置时,表示将查询上级日志记录器以确定生效的级别。 如果仍被解析为 NOTSET,则会记录所有事件。 在处理器上设置时,所有事件都将被处理。
logging.DEBUG 10 详细的信息,通常只有试图诊断问题的开发人员才会感兴趣。
logging.INFO 20 确认程序按预期运行。
logging.WARNING 30 表明发生了意外情况,或近期有可能发生问题(例如‘磁盘空间不足’)。 软件仍会按预期工作。
logging.ERROR 40 由于严重的问题,程序的某些功能已经不能正常执行
logging.CRITICAL 50 严重的错误,表明程序已不能继续执行

若设置了一个level,则只有高于或等于这个level的日志才能展示。比如,logger.setLevel(logging.ERROR),则只有logging.error('日志信息')logging.critical('日志信息')才能输出。

默认值是WARNING,即当等级大于等于WARNING才输出。

2.2 使用示例

示例1: 一步配置根日志器

一步配置,在根日志器上配置,默认输出到控制台, 本示例输出到指定生成的filename文件中。
根日志器初始化:logging.basicConfig(**kwargs)

# myapp.py
import logging
import time
logger = logging.getLogger(__name__)

def main():
    logging.basicConfig(filename = time.strftime('my-%Y-%m-%d.log'), level=logging.INFO,format = '%(asctime)s  %(levelname)-10s %(processName)s  %(name)s %(message)s', datefmt =  '%Y-%m-%d-%H-%M-%S')
    logger.info('Started') # 本陈旭创建的__name__ 日志器
    logging.debug('debug')  # 根日志器
    logging.info('info') 
    logging.warning('warning') 
    logging.error('error')
    logging.critical('critical')
    logging.log(logging.WARNING, 'another warning')
    logging.log(40, 'another error')

if __name__ == '__main__':
    main()

输出到my-2024-07-27.log文件

2024-07-27-14-55-05  INFO       MainProcess  __main__ Started
2024-07-27-14-55-05  INFO       MainProcess  root info
2024-07-27-14-55-05  WARNING    MainProcess  root warning
2024-07-27-14-55-05  WARNING    MainProcess  __main__ warning
2024-07-27-14-55-05  ERROR      MainProcess  root error
2024-07-27-14-55-05  CRITICAL   MainProcess  root critical
2024-07-27-14-55-05  WARNING    MainProcess  root another warning
2024-07-27-14-55-05  ERROR      MainProcess  root another error

更多格式输出可参考:format格式说明
注意:

  1. basicConfig() 设置的是根日志器的属性,调用应该在debug()info() 等的前面。因为它被设计为一次性的配置,只有第一次调用会进行操作,随后的调用不会产生有效操作。

示例2:多步配置子日志器

在子日志器上配置,常用配置如下:

# 日志文件固定大小
impo
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值