Python:logging 的巧妙设计
引言
logging 的基本用法网上很多,这里就不介绍了。在引入正文之前,先来看一个需求:
假设需要将某功能封装成类库供他人使用,如何处理类库中的日志?
数年前在一个 C# 开发的项目中,我用了这样的方法:定义一个 logging 基类,所有需要用到日志的类都继承这个基类,这个基类中定义一个 LogHandler 事件,该事件用于实现具体的记录日志动作,同时可以通过将类 A 的 LogHandler 委托挂到类 B 的 LogHandler 上,实现将两个类的日志信息添加到一起。
自从看了 python 中 logging 的实现方式,我发现我的做法真是弱爆了。
我在之前的博客 Python:logging.NullHandler 的使用 中介绍了 peewee 框架中的日志输出,简单来说就是 peewee 中定义了一个名为peewee 的 Logger 并添加了一个 NullHandler,调用者只需要为其添加具体的 Handler 就可以输出日志了,非常方便。

假设我们在主程序中也有一个 Logger,调用 peewee 后,我想将两个日志输出到同一个日志文件中去。显然将两个日志的 FileHandler 指向同一个日志文件是不可取的,存在并发抢占文件的风险。当然我们也可以将主程序中的 Logger 名字定为 peewee,但这不仅太 low 了,而且如果再调用一个库,其中也封装好了一个 Logger,就不好处理了。
树桩结构的 Logger
Logger 对象被设计为一个树形结构,它有一个 parent 属性。logging 中定义了一个名为 root 的 Logger 作为所有 Logger 的根节点,root 的 parent 属性为 None。root 是全局的。
当调用
logging.getLogger(name=None)
得到一个 Logger 对象的时候,如果 name 为 None,则返回根节点 root。如果 name 中含有 .,比如 name = 'a.b',这时如果已经存在了名为 a 的 Logger,则 a.b 为 a 的子节点,如果不存在名为 a 的 Logger,则 a.b 为 root 的子节点。
child logger 在完成对日志消息的处理后,默认会将日志消息传递给与它的 parent logger。因此,我们不必为一个应用程序中使用的所有 Logger 定义和配置 handlers,只需要为一个顶层的 Logger 配置 handlers,然后按照需要创建 child loggers 就可足够了。我们可以通过设置 Logger 的 propagate 属性设置为 False 来关闭这种传递机制。
什么意思呢,我们来看代码:
import logging
logA = logging.getLogger('a')
logA.setLevel(logging.DEBUG)
logA.addHandler(logging.StreamHandler())
logB = logging.getLogger('a.b')
logB.addHandler(logging.StreamHandler())
输出结果:
Logger A
Logger B
Logger B
之所以 Logger B 被输出了 2 次,是因为 logB 是 logA 的子节点,并且 logB 中也定义了 Handler,所以 logB 的 Handler 输出了一次,logA 的 Handler 也输出了一次,就 2 次了。如果想只输出一次,可以删掉 logB 中的 Handler。当然,这也是有用处的,尤其是当你手头没有日志管理工具的时候。例如,主程序中需要输出所有的日志,以便了解程序整体的运行顺序,而某模块的日志,你想单独输出一份,以便清晰了解模块中的报错或者是执行顺序。
之前 peewee 的例子也就很容易解决了,只需要将 peewee 日志的 parent 属性设置为主程序的日志就可以了。
结语
其实这是一个比较容易说明的问题,完全没必要写这么多。我并不想跟大家分享 python 中的 logging 是怎么用的,而是想和大家分享 logging 如此实现的一种思想,因为我遇到过这个问题,也设计了解决方案,然后被完爆了。
我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1ik0uj4dod1ui
Python:logging 的巧妙设计的更多相关文章
- Python logging 模块和使用经验
记录下常用的一些东西,每次用总是查文档有点小麻烦. py2.7 日志应该是生产应用的重要生命线,谁都不应该掉以轻心 有益原则 级别分离 日志系统通常有下面几种级别,看情况是使用 FATAL - 导致程 ...
- python logging详解及自动添加上下文信息
之前写过一篇文章日志的艺术(The art of logging),提到了输出日志的时候记录上下文信息的重要性,我认为上下文信息包括: when:log事件发生的时间 where:log事件发生在哪个 ...
- python logging模块,升级print调试到logging。
简介: 我们在写python程序的时候,很多时候都有bug,都是自己写的,自己造的孽,又的时候报错又是一堆,不知道是那部分出错了. 我这初学者水平,就是打print,看哪部分执行了,哪部分没执行,由此 ...
- 0x01 Python logging模块
目录 Python logging 模块 前言 logging模块提供的特性 logging模块的设计过程 logger的继承 logger在逻辑上的继承结构 logging.basicConfig( ...
- python logging模块可能会令人困惑的地方
python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...
- python logging 配置
python logging 配置 在python中,logging由logger,handler,filter,formater四个部分组成,logger是提供我们记录日志的方法:handler是让 ...
- Python LOGGING使用方法
Python LOGGING使用方法 1. 简介 使用场景 场景 适合使用的方法 在终端输出程序或脚本的使用方法 print 报告一个事件的发生(例如状态的修改) logging.info()或log ...
- python logging 日志轮转文件不删除问题
前言 最近在维护项目的python项目代码,项目使用了 python 的日志模块 logging, 设定了保存的日志数目, 不过没有生效,还要通过contab定时清理数据. 分析 项目使用了 logg ...
- python logging模块使用
近来再弄一个小项目,已经到收尾阶段了.希望加入写log机制来增加程序出错后的判断分析.尝试使用了python logging模块. #-*- coding:utf-8 -*- import loggi ...
随机推荐
- Python3实现ICMP远控后门(上)_补充篇
ICMP后门(上)补充篇 前言 在上一篇文章Python3实现ICMP远控后门(上)中,我简要讲解了ICMP协议,以及实现了一个简单的ping功能,在文章发表之后,后台很多朋友留言,说对校验和的计算不 ...
- 网络传输数据封装详解(IP,UDP,TCP)
IP数据包也叫IP报文分组,传输在ISO网络7层结构中的网络层,它由IP报文头和IP报文用户数据组成,IP报文头的长度一般在20到60个字节之间,而一个IP分组的最大长度则不能超过65535个字节. ...
- 嵌入Python系列 | 调用Python模块中无参数函数
开发环境 Python版本:3.6.4 (32-bit) 编辑器:Visual Studio Code C++环境:Visual Studio 2013 需求说明 在用VS2013编写的Win32程序 ...
- macbook 添加快捷启动服务
来至 Mac OS X: Launch Terminal from keyboard shortcut os x 上很多功能都可以通过Apple自家的Automator.app创建,且使用此方法可以为 ...
- Linux 普通用户之间免密登陆
目的: 同台机器之间实现普通用户之间的免密登陆: NN01 的user1 免密登陆 user2 不同机器之间实现普通用户之间的免密登陆 :NN01 的user1 免密登陆 NN01 的user1 一. ...
- 使用非阻塞ServerSocketChannel、SocketChannel代替ServerSocket和Socket
http://blog.csdn.net/timliang18601860/article/details/7104485
- UIAlertControl的使用对比与UIAlertView和UIActionSheet
1.UIAlertVIew以-(void)show的方法显示: - (void)viewDidLoad { [super viewDidLoad]; //UIAlertView的使用 [self sh ...
- Supervisor管理进程
Supervisor管理进程 转载 2016年04月14日 18:26:45 标签: supervisord 28344 Supervisor重新加载配置启动新的进程 liaojie 发布于 1年前, ...
- Spring mvc 原理浅析
2.2. 数据的绑定 前面说过了,SpringMVC是方法级的映射,那么Spring是如何处理方法签名的,又是如何将表单数据绑定到方法参数中的?下面我们就来讨论这个问题.2.2.1. 处理方法签名 首 ...
- Java 并行与并发
Java 并行与并发 注意两个词:并行(Concurrent) 并发(Parallel) 并行:是逻辑上同时发生,指在某一个时间内同时运行多个程序 并发:是物理上同时发生,指在某一个时间点同时运行多个 ...