- [Formater类](#Formater_174)
- [Filter类](#Filter_186)
+ [工作流程](#_189)
+ [使用logging四大组件日志输出案例](#logging_208)
官方介绍
概述
这个模块为应用与库实现了灵活的事件日志系统的函数与类。
使用标准库提提供的 logging API 最主要的好处是,所有的 Python 模块都可能参与日志输出,包括你自己的日志消息和第三方模块的日志消息。
这个模块提供许多强大而灵活的功能。如果你对 logging 不太熟悉的话, 掌握它最好的方式就是查看它对应的教程(详见右侧的链接)。
该模块定义的基础类和函数都列在下面。
- 记录器暴露了应用程序代码直接使用的接口。
- 处理器将日志记录(由记录器创建)发送到适当的目标。
- 过滤器提供了更精细的设施,用于确定要输出的日志记录。
- 格式器指定最终输出中日志记录的样式。
源码部分
python官方logging源码文档
:https://docs.python.org/zh-cn/3/library/logging.html#module-logging
日志教程
基础教程:
https://docs.python.org/zh-cn/3/howto/logging.html#basic-logging-tutorial
进阶教程:
https://docs.python.org/zh-cn/3/howto/logging.html#advanced-logging-tutorial
日志操作手册:
https://docs.python.org/zh-cn/3/howto/logging-cookbook.html
这些内容在官方文档都有详细的介绍,这里就不介绍了,我们把重点放在实际开发中的使用、注意事项以及执行的流程
日志相关概念
日志是一种可以追踪某些软件运行时所发生事件的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可以用一个可包含可选变量数据的消息来描述。此外,事件也有重要性的概念,这个重要性也可以被称为严重性级别(level)。
日志等级
DEBUG
INFO
NOTICE
WARNING
ERROR
CRITICAL
ALERT
EMERGENCY
日志字段信息与格式
- 事件发生时间
- 事件发生位置
- 事件的严重程度–日志级别
- 事件内容
输出一条日志时,日志内容和日志级别是需要开发人员明确指定的。对于而其它字段信息,只需要是否显示在日志中就可以了。
日志功能的实现
几乎所有开发语言都会内置日志相关功能,或者会有比较优秀的第三方库来提供日志操作功能,比如:log4j,log4php等。它们功能强大、使用简单。Python自身也提供了一个用于记录日志的标准库模块–logging。
logging模块总结
logging模块提供了两种记录日志的方式
- 第一种方式是使用logging提供的模块级别的函数
函数 | 说明 |
---|---|
logging.debug(msg, *args, **kwargs) | 创建一条严重级别为DEBUG的日志记录 |
logging.info(msg, *args, **kwargs) | 创建一条严重级别为INFO的日志记录 |
logging.warning(msg, *args, **kwargs) | 创建一条严重级别为WARNING的日志记录 |
logging.error(msg, *args, **kwargs) | 创建一条严重级别为ERROR的日志记录 |
logging.critical(msg, *args, **kwargs) | 创建一条严重级别为CRITICAL的日志记录 |
logging.log(level, *args, **kwargs) | 创建一条严重级别为level的日志记录 |
logging.basicConfig(**kwargs) | 对root logger进行一次性配置 |
- 第二种方式是使用Logging日志系统的四大组件
组件 | 说明 |
---|---|
loggers | 提供应用程序代码直接使用的接口 |
handlers | 用于将日志记录发送到指定的目的位置 |
filters | 提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略) |
formatters | 用于控制日志信息的最终输出格式 |
使用logging提供的模块级别的函数记录日志
简单的案例
logging.log(logging.DEBUG, "This is a debug log.")
logging.log(logging.INFO, "This is a info log.")
logging.log(logging.WARNING, "This is a warning log.")
logging.log(logging.ERROR, "This is a error log.")
logging.log(logging.CRITICAL, "This is a critical log.")
# 输出结果
# WARNING:root:This is a warning log.
# ERROR:root:This is a error log.
# CRITICAL:root:This is a critical log.
我们发现前两条日志并没有输出,这是为什么呢?
这是因为logging模块提供的日志记录函数所使用的日志器设置的默认日志级别
是WARNING
,因此只有WARNING
级别的日志记录以及大于
它的ERROR
和CRITICAL
级别的日志记录被输出了,而小于
它的DEBUG
和INFO
级别的日志记录被丢弃了。
而且输出的格式也是固定的,
之所以会这样输出,是因为logging模块提供的日志记录函数所使用的日志器设置的日志格式默认
是BASIC_FORMAT
,其值为:"%(levelname)s:%(name)s:%(message)s"
其实这些初始化的配置,都是在执行的过程中调用了logging.basicConfig(**kwargs)
,且不会向该方法传递任何参数,接下来我们详细看看baseConfig()
logging.basicConfig()函数说明
参数说明 | 描述 |
---|---|
filename | 指定日志输出目标文件的文件名,指定该设置项后日志信心就不会被输出到控制台了 |
filemode | 指定日志文件的打开模式,默认为’a’。需要注意的是,该选项要在filename指定时才有效 |
format | 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。 |
datefmt | 指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效 |
level | 指定日志器的日志级别 |
stream | 指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。需要说明的是,stream和filename不能同时提供,否则会引发 ValueError异常 |
style | Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为’%’、’{‘和’$’,默认为’%’ |
handlers | Python 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。需要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。 |
logging模块定义的格式字符串字段
使用配置的日志输出案例
import logging
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"
logging.basicConfig(filename='log.log',level=logging.INFO,format=LOG_FORMAT,datefmt=DATE_FORMAT)
logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")
logging模块日志流处理流程
我们先来看一下四大组件
之间的关系描述
- 日志器:
Logger
需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等; - 处理器:
handler
,不同的处理器可以将日志输出到不同的位置 - 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
- 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
- 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。
简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。
四大组件的常用方法
Logger类
Logger对象有3个任务要做
1)向应用程序代码暴露几个方法,使应用程序可以在运行时记录日志消息;
2)基于日志严重等级(默认的过滤设施)或filter对象来决定要对哪些日志进行后续处理;
3)将日志消息传送给所有感兴趣的日志handlers。
常用的配置方法
方法 | 描述 |
---|---|
Logger.setLevel() | 设置日志器将会处理的日志消息的最低严重级别 |
Logger.addHandler() 和 Logger.removeHandler() | 为该logger对象添加 和 移除一个handler对象 |
Logger.addFilter() 和 Logger.removeFilter() | 为该logger对象添加 和 移除一个filter对象 |
Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical() | 创建一个与它们的方法名对应等级的日志记录 |
Logger.exception() | 创建一个类似于Logger.error()的日志消息 |
Logger.log() | 需要获取一个明确的日志level参数来创建一个日志记录 |
说明:
- Logger.exception()与Logger.error()的区别在于:Logger.exception()将会输出堆栈追踪信息,另外通常只是在一个exception handler中调用该方法。
- Logger.log()与Logger.debug()、Logger.info()等方法相比,虽然需要多传一个level参数,显得不是那么方便,但是当需要记录自定义level的日志时还是需要该方法来完成。
关于logger的层级结构与有效等级的说明:
- logger的名称是一个以’.‘分割的层级结构,每个’.‘后面的logger都是’.'前面的logger的children,例如,有一个名称为 foo 的logger,其它名称分别为 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的后代。
- logger有一个"有效等级(effective level)"的概念。如果一个logger上没有被明确设置一个level,那么该logger就是使用它parent的level;如果它的parent也没有明确设置level则继续向上查找parent的parent的有效level,依次类推,直到找到个一个明确设置了level的祖先为止。需要说明的是,root logger总是会有一个明确的level设置(默认为 WARNING)。当决定是否去处理一个已发生的事件时,logger的有效等级将会被用来决定是否将该事件传递给该logger的handlers进行处理。
- child loggers在完成对日志消息的处理后,默认会将日志消息传递给与它们的祖先loggers相关的handlers。因此,我们不必为一个应用程序中所使用的所有loggers定义和配置handlers,只需要为一个顶层的logger配置handlers,然后按照需要创建child loggers就可足够了。我们也可以通过将一个logger的propagate属性设置为False来关闭这种传递机制。
Handler类
Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:
1)把所有日志都发送到一个日志文件中;
2)把所有严重级别大于等于error的日志发送到stdout(标准输出);
3)把所有严重级别为critical的日志发送到一个email邮件地址。
这种场景就需要3个不同的handlers,每个handler复杂发送一个特定严重级别的日志到一个特定的位置。
常用的handler
Handler | 描述 |
---|---|
logging.StreamHandler | 将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。 |
logging.FileHandler | 将日志消息发送到磁盘文件,默认情况下文件大小会无限增长 |
logging.handlers.RotatingFileHandler | 将日志消息发送到磁盘文件,并支持日志文件按大小切割 |
logging.hanlders.TimedRotatingFileHandler | 将日志消息发送到磁盘文件,并支持日志文件按时间切割 |
logging.handlers.HTTPHandler | 将日志消息以GET或POST的方式发送给一个HTTP服务器 |
logging.handlers.SMTPHandler | 将日志消息发送给一个指定的email地址 |
logging.NullHandler | Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免’No handlers could be found for logger XXX’信息的出现。 |
Formater类
Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
Formatter类的构造方法定义如下:
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、学习软件
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
三、全套PDF电子书
书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。
四、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
五、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!