大师兄的Python学习笔记(十): 多进程和多线程
大师兄的Python学习笔记(八): 异常处理
一、关于logging模块和日志
1.关于日志文件
- 日志文件是记录在操作系统或其他软件运行中发生的事件或在通信软件的不同用户之间的消息的文件。
- 生成日志文件的过程是I/O操作,对于程序来讲速度很慢,所以不要过于频繁的生成日志。
1)日志的功能
- 了解程序的运行情况,是否正常。
- 记录和追踪软件运行时发生的事件。
- 在发生故障时进行故障分析与问题定位。
2)日志通常包含的内容
- 事件发生时间
- 事件发生位置
- 日志的级别
- 事件内容
3)日志的不同级别
- 不同的用户关注不同的日志信息
级别 含义 DEBUG 最详细的日志信息,用于程序的问题诊断,通常是开发者使用。 INFO 详细程度仅次于DEBUG,通知用户一个操作或状态发生了变化,非技术人员接触的最详细的信息。 NOTICE 一般性的重要事件,普通运营人员日常会看的信息。 WARNING 警告信息,某个错误可能已经或将要发生,但此时程序还是正常运行的,普通运营人员会关注的信息。 ERROR 发生了错误,不需要立即采取行动,但必须记录下来以备检测。 CRITICAL 发生了严重错误,导致某些功能不能正常运转,可能会给管理者发邮件了。 ALERT 必须立即采取行动,比如整个网站全挂了,可能会给管理者发短信了。 EMERGENCY 紧急状态,系统无法继续使用。
2.关于logging模块
1)logging模块介绍
- logging模块是Python的内置模块,会随着Python一起默认安装,可以通过
import logging
导入模块。- 主要用于生成、管理和输出运行日志。
- 可以设置输出日志的等级、日志保存路径、日志文件回滚等;
- 可以自定义日志的输出方式和输出位置。
2)logging模块的等级
- logging模块允许自定义日志等级(不推荐,容易引起混乱)。
- 默认等级包括:
级别 含义 DEBUG 最详细的日志信息,用于程序的问题诊断,通常是开发者使用。 INFO 详细程度仅次于DEBUG,通知用户一个操作或状态发生了变化,非技术人员接触的最详细的信息。 WARNING 警告信息,某个错误可能已经或将要发生,但此时程序还是正常运行的,普通运营人员会关注的信息。 ERROR 发生了错误,不需要立即采取行动,但必须记录下来以备检测。 CRITICAL 发生了严重错误,导致某些功能不能正常运转,可能会给管理者发邮件了。
二、logging模块的使用
- logging模块使用有两种方式:
序号 | 方法 |
---|---|
方法一 | 使用logging提供的模块级别的函数(封装了logging日志系统相关类) |
方法二 | 使用Logging日志系统的四大组件 |
1.方法一:使用logging提供的模块级别的函数
1.1 第一步:使用 logging.basicConfig()函数配置日志
- 可以调整日志级别、输出格式等
- 只有在第一次使用时生效。
- 全部参数如下:
参数 含义 filename 指定日志文件名 filemode 和file函数意义相同,指定日志文件的打开模式,'w'或'a' datefmt 指定时间格式,同time.strftime() level 设置日志级别,默认为logging.WARNING stream 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略 format 指定输出的格式和内容,format可以输出很多有用信息 >>>import logging >>>logging.basicConfig( >>> filename='test_log.txt', >>> filemode='a', >>> datefmt='%Y-%m-%d %H:%M:%S %a' , >>> level=logging.WARNING # 默认为logging.Warning >>>)
- format中可以使用的信息参数如下:
参数 含义 %(levelno)s 打印日志级别的数值 %(levelname)s 打印日志级别名称 %(pathname)s 打印当前执行程序的路径,其实就是sys.argv[0] %(filename)s 打印当前执行程序名 %(funcName)s 打印日志的当前函数 %(lineno)d 打印日志的当前行号 %(asctime)s 打印日志的时间 %(thread)d 打印线程ID %(threadName)s 打印线程名称 %(process)d 打印进程ID %(message)s 打印日志信息 >>>import logging >>>logging.basicConfig( >>> format="%(asctime)s %(name)s %(levelname)s %(message)s" >>>)
1.2 第二步:调用函数生成日志**
函数 说明 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进行一次性配置 #Python代码 >>>import logging >>>logging.basicConfig( >>> filename='test_log.txt', >>> filemode='a', >>> datefmt='%Y-%m-%d %H:%M:%S %a' , >>> level=logging.WARNING, # 默认为logging.Warning >>> format="%(asctime)s %(name)s %(levelname)s %(message)s" >>>) >>>logging.warning('这里有个问题需要注意一下!') >>>logging.error('这里发生了一个错误!') # test_log.txt >>>2020-01-04 18:19:05 Sat root WARNING 这里有个问题需要注意一下! >>>2020-01-04 18:19:05 Sat root ERROR 这里发生了一个错误!
2.方法二:使用Logging日志系统的四大组件
2.1 关于四大组件
组件名称 对应类名 功能描述 日志器 Logger 提供了应用程序可一直使用的接口 处理器 Handler 将logger创建的日志记录发送到合适的目的输出 过滤器 Filter 提供了更细粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录 格式器 Formatter 决定日志记录的最终输出格式 2.2 四大组件的工作流程**
- 日志器(logger)将日志的分身分配给多个处理器(handler);
- 每个处理器(handler)可以设置自己的过滤器(filter)实现日志过滤,按权限保留日志;
- 每个处理器(handler)可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。
2.3 logger类
1)logger类的功能
- 向应用程序代码暴露几个方法,使应用程序可以在运行时记录日志消息;
- 基于日志严重等级(默认的过滤设施)或filter对象来决定要对哪些日志进行后续处理;
- 将日志消息传送给所有感兴趣的日志handlers。
2)logger类的配置方法
方法 描述 Logger.setLevel() 设置日志器将会处理的日志消息的最低严重级别 Logger.addHandler() 和 Logger.removeHandler() 为该logger对象添加 和 移除一个handler对象 Logger.addFilter() 和 Logger.removeFilter() 为该logger对象添加 和 移除一个filter对象 >>>import logging >>># 创建logger >>>logger = logging.getLogger() >>># 创建handler >>>handler1 = logging.StreamHandler() >>>handler2 = logging.FileHandler(filename='testlog.txt') >>># 创建filter >>>filter = logging.Filter() >>># 为logger设置处理日志的最低严重级别 >>>logger.setLevel(logging.WARNING) >>># 为logger添加handler >>>logger.addHandler(handler1) >>>logger.addHandler(handler2) >>># 为logger添加filter >>>logger.addFilter(filter)
3)logger类的创建日志和消息发送方法
方法 描述 Logger.debug()
Logger.info()
Logger.warning()
Logger.error()
Logger.critical()创建一个与它们的方法名对应等级的日志记录 Logger.exception() 创建一个类似于Logger.error()的日志消息 Logger.log() 需要获取一个明确的日志level参数来创建一个日志记录 # 先配置logger >>>import logging >>># 创建logger >>>logger = logging.getLogger() >>># 创建handler >>>handler1 = logging.StreamHandler() >>># 为logger设置处理日志的最低严重级别 >>>logger.setLevel(logging.DEBUG) >>># 为logger添加handler >>>logger.addHandler(handler1) # 使用logger.warning >>>logger.warning('this is a warning message!') this is a warning message! # 使用logger.exception >>>try: >>> 1/0 >>>except ZeroDivisionError as e: >>> logger.exception(e,exc_info=True) division by zero Traceback (most recent call last): File "
", line 2, in 1/0 ZeroDivisionError: division by zero # 使用logger.log >>>try: >>> 1/0 >>>except ZeroDivisionError as e: >>> logger.log(level=logging.CRITICAL, msg=e, exc_info=True) division by zero Traceback (most recent call last): File " ", line 2, in 1/0 ZeroDivisionError: division by zero 2.4 handler类
1)handler类的功能
- logger可以添加多个handler。
- 可以将消息按照level分发到handler指定的位置。
- 比如:文件、网络、邮件等
2)handler类的配置方法
方法 描述 Handler.setLevel(lel) 指定被处理的信息级别,低于lel级别的信息将被忽略 Handler.setFormatter() 给这个handler选择一个格式 Handler.addFilter(filt)
Handler.removeFilter(filt)新增或删除一个filter对象 >>>import logging >>># 创建logger >>>logger = logging.getLogger() >>># 创建handler >>>handler1 = logging.StreamHandler() >>>handler2 = logging.FileHandler(filename='testlog.txt') >>># 创建filter >>>filter = logging.Filter() >>># 创建formatter >>>formatter = logging.Formatter() >>># 为logger添加handler >>>logger.addHandler(handler1) >>>logger.addHandler(handler2) >>># 配置handler >>>handler1.setLevel(logging.DEBUG) >>>handler1.setFormatter(formatter) >>>handler1.addFilter(filter)
3)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'信息的出现。 >>>import logging >>># 创建logger >>>logger = logging.getLogger() >>># 创建handler >>>handler1 = logging.StreamHandler() >>>handler2 = logging.FileHandler(filename='testlog.txt') >>># 创建filter >>>filter = logging.Filter() >>># 创建formatter >>>formatter = logging.Formatter() >>># 为logger添加handler >>>logger.addHandler(handler1) >>>logger.addHandler(handler2) >>># 配置handler >>>handler1.setLevel(logging.DEBUG) >>>handler1.setFormatter(formatter) >>>handler1.addFilter(filter) >>># 生成一条log >>>logger.warning('this is a warning message!') this is a warning message! #'testlog.txt'文件 this is a warning message!
2.5 formater类
1)formater类的功能
- Formater对象用于配置日志信息的最终顺序、结构和内容。
- 与logging.Handler基类不同的是,应用代码可以直接实例化formatter类。
- 另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
2)formater的使用方法
- formater了构造方法可接收以下三个参数:
参数 描述 fmt 指定消息格式化字符串,如果不指定该参数则默认使用message的原始值(参考1.1中的format参数) datefmt 指定日期格式字符串,如果不指定该参数则默认使用"%Y-%m-%d %H:%M:%S" style Python 可取值为 '%', '{'和 '$',如果不指定该参数则默认使用'%' >>>import logging >>># 创建logger >>>logger = logging.getLogger() >>># 创建handler >>>handler1 = logging.StreamHandler() >>>handler2 = logging.FileHandler(filename='testlog.txt') >>># 创建filter >>>filter = logging.Filter() # 创建formatter >>>formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y%b%d-%H:%M:%S") # 使用formatter >>># 为logger添加handler >>>logger.addHandler(handler1) >>>logger.addHandler(handler2) >>># 配置handler >>>handler1.setLevel(logging.DEBUG) >>>handler2.setFormatter(formatter) >>>handler1.addFilter(filter) >>># 生成一条log >>>logger.warning('this is a warning message!') 2020Jan06-21:28:23 WARNING this is a warning message! #'testlog.txt'文件 2020Jan06-21:30:44 WARNING this is a warning message!
2.6 filter类
1)filter类的功能
- Filter可以被Handler和Logger用来做比level更细粒度的、更复杂的过滤功能。
- Filter是一个过滤器基类,它只允许某个logger层级下的日志事件通过过滤。
2)filter类的使用方法
- 首先配置filter,之后将filter添加到logger或handler中。
>>>import logging >>># 创建logger >>>logger = logging.getLogger() >>># 创建filter >>>class MyFilter(logging.Filter): >>> def filter(self,record): >>> if record.role == "admin": >>> return True >>> else: >>> return False >>># 添加filter >>>filter = MyFilter() >>>logger.addFilter(filter) >>># 生成一条log >>>logger.warning('this is a warning message!',extra={"role":"admin"}) >>>logger.critical('this is a critical message!',extra={"role":"user"}) # 这条被filter过滤掉了 >>>logger.removeFilter(filter) # 为了避免重复发生log信息 this is a warning message!
参考资料
- https://blog.csdn.net/u010138758/article/details/80152151 J-Ombudsman
- https://www.cnblogs.com/zhuluqing/p/8832205.html moisiet
- https://www.runoob.com 菜鸟教程
- http://www.tulingxueyuan.com/ 北京图灵学院
- http://www.imooc.com/article/19184?block_id=tuijian_wz#child_5_1 两点水
- https://blog.csdn.net/weixin_44213550/article/details/91346411 python老菜鸟
- https://realpython.com/python-string-formatting/ Dan Bader
- https://www.liaoxuefeng.com/ 廖雪峰
- https://blog.csdn.net/Gnewocean/article/details/85319590 新海说
- https://www.cnblogs.com/Nicholas0707/p/9021672.html Nicholas
- 《Python学习手册》Mark Lutz
- 《Python编程 从入门到实践》Eric Matthes
本文作者:大师兄(superkmi)