全栈工程师开发手册 (作者:栾鹏)

python教程全解

logging结构

logging模块是Python内置的一个强大易用的日志模块。

  • 整体上来说,日志管理最大的结构是Manager,Manager管理所有的Logger,但你不用去管这个东西,它是藏在背后默默干活的。
  • Logger里最根部是一个RootLogger,name是root,其他所有Logger都是在这个Logger下,通过名字,形成父子、子孙的树杈结构。
  • Logger里面有一些东西,Filter、Handler、LogRecord、Formatter,可以看作是一些配置,各自有各自的作用,接下来会介绍。
  • 还能用LoggerAdapter对Logger进行一定的包装,一般我们用的很少。

logger是一个树结构,默认有个根root,其他logger都是其上的枝桠,比如创建一个name=’A.B’的logger,其实际结构就是 root-A-B

再创建一个name=’A.C.D’的logger,结构变为:

level 输出级别

在输出log的时候,不能所有日志都输出出来,而是有所选择,比如有时候我们只希望看到warning以上严重程度的,如果有太多info、debug会让log可读性变得很差。

我们可以通过设置logger的level来实现这一点。在logging中,将level设置如下:

LevelName LevelValue
CRITICAL/ FATAL 50
ERROR 40
WARNING/ WARN 30
INFO 20
DEBUG 10
NOTSET 0

示例:

import logging
logger = logging.getLogger('test')
logging.basicConfig()  # basicConfig是logging提供的简单的配置方法,不用basicConfig则需要手动添加handler
logger.setLevel(logging.INFO)  # 输出所有大于等于INFO级别的log
logger.info('I am <info> message.')
logger.debug('I am <debug> message.')  # 不输出

输出:

INFO:test:I am <info> message.

要注意的是: root 的默认级别是 WARNING!, 而且logger实际输出时的level是取决于EffectiveLevel,即从该级往上走,遇到的第一个level不为0的logger的level,也就是说如果你创建了logger,而没有为其设置level,那它默认是NOTSET,程序会往上层找,直到root,而root级别是WARNING,所以可能会导致没有输出日志。

handler日志输出目的地

我们写日志一个很重要的问题就是把日志输出到什么地方去,我们可能希望某些日志在console打印出来,可能希望有更详细的日志输出到log文件里去。怎么控制这些输出就需要用handler了。

import logging
logger = logging.getLogger('test')
logger.addHandler(logging.StreamHandler())  # 添加StreamHandler
logger.setLevel(logging.INFO)  # 输出所有大于INFO级别的log
logger.info('I am <info> message.')
logger.debug('I am <debug> message.')  # 不输出

我们把上面的例子稍微改动了一下,可以看到输出如下,输出到了console里。在pycharm中都是显示在输出窗口中。只不过缺少了INFO:的级别类型

I am <info> message.

这就是logging提供的最基本的一个handler,其他各种handler都是从这个handler继承发展来的。理论上可以把日志输出到各种流中,stderr、文件、socket等都可以。当然logging已经将各种流handler封装好了。

import logging
logger = logging.getLogger('test')
logger.addHandler(logging.StreamHandler())
logger.addHandler(logging.FileHandler('test.log'))  # 再添一个FileHandler
logger.setLevel(logging.INFO)  # 输出所有大于INFO级别的log
logger.info('I am <info> message.')
logger.debug('I am <debug> message.')  # 不输出

可以看到,info不仅仅输出到了console中,还在当前文件夹下创建了一个test.log文件并输出到了该文件中。在logging.handlers中还封装了一堆更高级的handlers,可以了解下,尤其是RotatingFileHandler和TimedRotatingFileHandler,可以把你的日志按一定规则分割成多份。你也可以自己封装handler哦,网上有人这么干的。

上面我们看到了logger的级别,可以控制这个logger要输出什么级别的log。但这里我们发现可以在logger里添加handler,控制输出log到哪里,明显发现,其实我们想要在不同的handler里输出不同级别的日志。

比如我们想要在console里输出warning以上的日志,在log文件里输出debug以上的日志,该怎么办呢?

handler也是有级别的。

import logging
logger = logging.getLogger('test')
logger.setLevel(logging.INFO)  # 输出所有大于INFO级别的log# 添加StreamHandler,并设置级别为WARNING
stream_hdl = logging.StreamHandler()
stream_hdl.setLevel(logging.WARNING)
logger.addHandler(stream_hdl)
# 添加FileHandler,并设置级别为DEBUG
file_hdl = logging.FileHandler('test.log')
file_hdl.setLevel(logging.DEBUG)
logger.addHandler(file_hdl)logger.info('I am <info> message.')
logger.debug('I am <debug> message.')  # 不输出

logger实例的log()函数,例如info()和debug()函数先针对logger实例的级别进行过滤,不超过logger实例级别的log()函数,不会被加载到logger实例中。

在这段代码中logger实例的等级为INFO,所以info()和debug()函数只有info函数会被记录到logger实例中。

logger实例中记录的log()函数再被StreamHandler和FileHandler根据各自的级别进行筛选。

这段代码中StreamHandler级别为WARNING,而FileHandler的级别为DEBUG,所以记录在logger实例中的info()函数只在FileHandler中输出,也就是只有在test.log函数中输出。

I am <info> message.

formatter —— 输出日志的格式

细心的话可以发现,我们后来自己添加的handler输出的log是没有格式的,就仅仅是输出而已。但basicConfig()输出的log是有格式的(虽然很丑)。

不同在于basicConfig()中的handler是带有formatter的。我们要添加formatter就需要用到logging中的另一个类Formatter

import logging
logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG)  # 输出所有大于INFO级别的log
fmt = logging.Formatter('%(name)s - %(levelname)s - %(asctime)s - %(message)s')
# 添加StreamHandler,并设置级别为WARNING
stream_hdl = logging.StreamHandler()
stream_hdl.setLevel(logging.DEBUG)
stream_hdl.setFormatter(fmt)
logger.addHandler(stream_hdl)
# 添加FileHandler,并设置级别为DEBUG
file_hdl = logging.FileHandler('test.log')
file_hdl.setLevel(logging.DEBUG)
file_hdl.setFormatter(fmt)
logger.addHandler(file_hdl)logger.info('I am <info> message.')
logger.debug('I am <debug> message.')  # 不输出

是不是漂亮多了,logging的formatter可以输出的不止这几个信息,还有很多:

  • %(name)s ——logger实例的名称
  • %(levelno)s ——等级编号,为(DEBUG, INFO, WARNING, ERROR, CRITICAL)对应的编号
  • %(levelname)s ——等级名称,为 (“DEBUG”, “INFO”, “WARNING”, “ERROR”, “CRITICAL”)中的一个
  • %(pathname)s ——触发log的文件的全路径
  • %(filename)s ——触发log的文件的文件名
  • %(module)s ——触发log的模块名
  • %(lineno)d ——触发log的代码行数
  • %(funcName)s ——函数名
  • %(created)f ——log记录的创建时间
  • %(asctime)s ——log记录的文本时间
  • %(msecs)d ——创建时间对应的毫秒级时间戳
  • %(relativeCreated)d ——应用启动到当前记录被加载之间的时间差
  • %(thread)d ——线程id
  • %(threadName)s ——线程名称
  • %(process)d ——进程id
  • %(message)s ——日志记录的消息显示

配置logger

我们可以通过多种途径配置logger,像上面用过的basicConfig()(没有用参数,可以自己阅读源码,很简单的几个参数),或者像上面的例子手动添加handler、设置formatter,logging还给了我们其他高级的配置方法:

logging.config里有多种配置方法,像fileConfig,可以直接读一个文件;像dictConfig,可以传一个dict进行配置(django就是这么配置的);似乎还能起个socket,来实时修改config,听起来很吊的样子。

python测试系列教程 —— 调试日志logging相关推荐

  1. python测试系列教程——python+Selenium+chrome自动化测试框架

    全栈工程师开发手册 (作者:栾鹏) python教程全解 需要的环境 浏览器(Firefox/Chrome/IE-) Python Selenium Selenium IDE(如果用Firefox) ...

  2. python测试系列教程 —— 单元测试unittest

    全栈工程师开发手册 (作者:栾鹏) python教程全解 unittest是xUnit系列框架中的一员,如果你了解xUnit的其他成员,那你用unittest来应该是很轻松的,它们的工作方式都差不多. ...

  3. python测试系列教程 —— YAML配置文件语法教程

    全栈工程师开发手册 (作者:栾鹏) python教程全解 YML文件格式是YAML (YAML Aint Markup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数据数据 ...

  4. python数据挖掘系列教程——PySpider框架应用全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python数据挖掘系列教程--PySpider框架应用全解. PySpider介绍 pyspider上手更简单,操作更加简便,因为它增加了 ...

  5. python基础系列教程——数据结构(列表、元组、字典、集合、链表)

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 基本顺序存储结构--列表与元组 Python中的基本顺序存储结构是列表与元组,在操作的复杂度上和数组完全相同,其中列表是可变数据类型, ...

  6. Python编程系列教程第12讲——属性和方法

    视频地址:http://v.youku.com/v_show/id_XNTgyOTg4NjQ4.html 普及网络安全知识,推动信息技术发展. 为祖国的网络安全撑起一片蓝天,为网络安全爱好者构建一方家 ...

  7. Python编程系列教程第16讲——拷贝自身到系统目录

    分享知识,分享快乐,收获友谊,收获财富! 大家好,我是数字雨,QQ:798033502 http://itbook.taobao.com/ 今天给大家带来的教程是<Python编程系列教程第16 ...

  8. python爬取图片教程-推荐|Python 爬虫系列教程一爬取批量百度图片

    Python 爬虫系列教程一爬取批量百度图片https://blog.csdn.net/qq_40774175/article/details/81273198# -*- coding: utf-8 ...

  9. Python编程系列教程第13讲——隐藏数据和封装

    视频地址:http://www.56.com/u88/v_OTM5NjU0MjE.html#fromoutpvid=OTM5NjU0MjE 普及网络安全知识,推动信息技术发展. 为祖国的网络安全撑起一 ...

最新文章

  1. ETH网络要爆炸,未来Token的最佳选择注定是BCH
  2. CF641D. Little Artem and Random Variable
  3. 2019阿里云开年Hi购季满返活动火热报名中!
  4. 实验一 线性表的顺序存储与实现_数据结构篇之单链表的创建以及实现
  5. __name__ == ‘__main__‘的原理
  6. win11杜比视界音效怎么打开 window11开启杜比视界音效的步骤方法
  7. jquery版瀑布流
  8. js 验证文本框为数字的正则表达式
  9. 计算机c盘要满了电脑会卡吗,C盘满了 电脑卡顿了,怎么清理空间
  10. 微信8.0自动发送炸弹python脚本
  11. PHP仿金蝶云ERP进销存网络多仓版源码
  12. windows10下超级好用的截屏自带快捷键
  13. 利用IPV6实现宿舍远程连接实验室并免费上网
  14. LittleVGL开发之显示中文字体以及矢量图标
  15. html标签加载状态,如何让html页面数据没有加载完前显示loading加载中
  16. 【论文写作】总结一下心得体会
  17. 全国计算机考试 mysql_全国计算机等级考试二级MySQL试题及答案
  18. java 压缩图片大小
  19. windows10家庭版个人电脑提升网速
  20. WGestures - 鼠标手势工具软件,高手必备效率神器!

热门文章

  1. win10语音识别的设置和开启
  2. 谷歌开源语音识别AI技术,可以从人群中区分每个人的发言
  3. supercharge快充_电荷泵?双电芯?高压低流?盘点目前最全快充技术
  4. Node.js异步编程~超级详细哦
  5. 【linux笔记】linux权限命令
  6. JAVA编写的使用Socket模拟Http的GET操作
  7. 同一主机的多个子进程使用同一个套接字_如何在Go语言中使用Websockets:最佳工具与行动指南...
  8. cad lisp 法兰6_南昌平板法兰加工设备_山东平安数控机械有限公司
  9. hibernate4 could not initialize proxy - no Session
  10. oracle存储过程数量,Oracle:存储过程的可变参数数量