日志(logging模块)
1. 为什么要使用日志(作用)
在学习过程中,写一个小程序或小demo时,遇到程序出错时,我们一般会将一些信息打印到控制台进行查看,方便排查错误。这种方法在较小的程序中很实用,但是当你的程序变大,或是说在实际的工程项目中,代码量都是很大的,代码量一大,不可控因素就多,再将信息打印到控制台进行查看是非常不方便的,此时就需要使用日志来记录程序运行过程中的相关信息,监控程序的运行情况。
2. 基础概念
我们在程序中会使用print打印一些信息以供我们判断程序的运行情况,什么时候需要使用print打印一些信息以及在什么位置使用print,这些都是根据程序自身以及个人的经验。使用日志和使用print是相似的,不同的时,日志具有多种形式来记录一些信息,例如 logging.FileHandler ****将日志信息文件写入文件,logging.handlers.SMTPHandler 将日志信息通过SMTP发送到一个电子邮件地址。
记录和处理日志信息的方式有很多种,logging库中提供了许多方法:https://docs.python.org/zh-cn/3/library/logging.handlers.html# 本文只记录 StreamHandler和 FileHandler 的使用方法。
logging库虽然提供了多种方法来记录和处理日志信息,但并不是什么信息都需要记录的,我们往往会根据程序中各个模块的重要程度来决定是否需要记录信息以及记录哪些信息。logging库根据事件的重要性提供了以下几个级别:
| 级别 | 使用时机 |
|---|---|
| DEBUG | 细节信息,仅当诊断问题时适用。 |
| INFO | 确认程序按预期运行,和print使用类似。 |
| WARNING | 表明有已经或即将发生的意外(例如:磁盘空间不足,数值运算产生精度丢失等)。程序仍按预期进行。 |
| ERROR | 由于严重的问题,程序的某些功能已经不能正常执行。 |
| CRITICAL | 严重的错误,表明程序已不能继续执行。 |
级别大小:DEBUG < INFO < WARNING <ERROR < CRITICAL
划分处理等级的目的是为了针对不同的情况来记录有用的信息,方便有效地监控程序的运行状况,当程序出错时也能方便的定位到。因此在使用logging库记录和处理日志信息前,需要先设定处理等级,默认的等级为 WARNING,当记录和处理日志信息时,只处理大于等于该等级的日志信息。
3. logging库的一些简单使用案例
3.1 像print一样打印日志信息
使用debug()、info()、warning()、error()、critical() 方法分别打印对应的级别及以上的信息,因为默认的级别为 WARNING,所以只会对warning()、error()、critical() 中的信息进行打印。
import logging
if __name__ == "__main__":
logging.debug("the message of debug")
logging.info("the message of debug")
logging.warning("the message of warning")
logging.error("the message of error")
logging.critical("the message of critical")
输出结果:
WARNING:root:the message of warning
ERROR:root:the message of error
CRITICAL:root:the message of critical
3.2 设置级别
使用 basicConfig() 方法设置级别,传入关键字参数 level ,参数值为对应级别的字符串形式。
import logging
if __name__ =="__main__":
logging.basicConfig(level='DEBUG')
logging.debug("the message of debug")
logging.info("the message of debug")
logging.warning("the message of warning")
logging.error("the message of error")
logging.critical("the message of critical")
输出结果:
DEBUG:root:the message of debug
INFO:root:the message of debug
WARNING:root:the message of warning
ERROR:root:the message of error
CRITICAL:root:the message of critical
3.3 在日志中打印变量信息
默认使用 printf 风格的方式进行字符串格式化。
import logging
if __name__ == "__main__":
name = "张三"
age = 24
logging.warning("%s的年龄为%s岁", name, age)
# 也可以使用format的方式进行字符串格式化
logging.warning("{}的年龄为{}岁".format(name, age))
输出结果:
WARNING:root:张三的年龄为24岁
3.4 更改日志信息显示的格式
对于可以出现在格式字符串中的全部内容,可以参考官方文档 LogRecord 属性 。
我们可以将日志信息的显示格式使用关键字 format 设置为:
format='%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s'
记录时间 - 记录器的名称 - 事件等级 - 产生日志信息的源文件名 - 所在函数名 - 提示信息
import logging
def main():
logging.basicConfig(format='%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s',
level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
if __name__ == "__main__":
main()
输出结果:
2022-04-19 15:30:02,404: root: DEBUG: logging_demo.py: main: This message should appear on the console
2022-04-19 15:30:02,404: root: INFO: logging_demo.py: main: So should this
2022-04-19 15:30:02,404: root: WARNING: logging_demo.py: main: And this, too
3.5 将日志信息写入文件
指定文件名 filename,文件写入方式 filenmode,默认写入方式为 a ;
import logging
def main():
fmt = '%(asctime)s: %(name)s: %(levelname)s: %(filename)s: %(funcName)s: %(message)s'
logging.basicConfig(filename="example.log", filemode='w', format=fmt, level="DEBUG")
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
if __name__ == "__main__":
main()
3.6 basicConfig
前面几个案例都使用到了 basicConfig 方法对打印和记录日志信息的行为进行设置,可以设置是将信息显示在控制台还是记录到文件中,可以设置显示或记录的内容格式,设置事件等级等,更详细的设置官方文档已经给出了很细致的解释。
4. 进一步使用
当程序规模变大,使用上面方式介绍的记录日志的方式就会显得捉襟见肘。下面介绍 logging库的进阶使用方式。
logging 库采用模块化的方式来记录日志信息,由以下四个核心组件组成:
Logger(记录器):根据记录器设置的等级捕获日志信息,并传递给对应的处理器;
Handler(处理器):将记录器传递过来的日志信息交给不同的处理器处理;
Filter(过滤器):更细粒度地控制要输出哪些日志记录;
Formatter(格式器):设置日志记录的输出格式;
下面说明这几个组件之间的联系及处理顺序:
- 首先通过
getLogger()方法一个指定名称的 Logger实例的引用,如果没提供名称,则返回root;logger = getLogger(name) - 为 Logger 实例设置捕获信息的等级,默认等级为 WARNING,
logger.setLevel('INFO') logger通过调用debug()、info()、warning()、error()、critical()这些方法来捕获日志信息;Logger只暴露接口供程序员调用,用来捕获日志信息,而不处理信息;只捕获大于等于其自身等级的信息;- 如果 logger 捕获了日志信息,则将日志信息传递给 Handler 进行处理;
- 每个 logger 可以有多个 Handler 处理捕获的日志信息,常用的 StreamHandler 和 FileHandler ,StreamHandler 将日志信息打印到终端显示,FileHandler 将日志信息记录写入到文件中;不同的Handler 也都具有等级属性,每个Handler 只会处理大于等于自身等级的日志信息;
其中 Filter 可以作用 Logger 和 Handler,用于更细粒度地控制捕获或输出哪些日志信息,本文不讨论 Filter 使用。
日志事件信息流程如下图所示:

整体代码框架如下:
# 实例化一个 Logger 对象,并记录一个名字
# 在命名记录器时使用的一个好习惯,是在每个使用日志记录的模块中使用模块级记录器
logger = logging.getLogger(__name__)
# 设置记录器捕获日志信息的等级
logger.setLevel("INFO")
# 实例化处理器对象
ch = logging.StreamHandler()
fh = logging.FileHandler("example.log")
# 设置处理器处理信息的等级
ch.setLevel("INFO")
fh.setLevel("WARNING")
# 设置处理器输出日志信息的格式
fmt = logging.Formatter('%(asctime)s: %(levelname)s: %(name)s: %(filename)s: %(message)s')
ch.setFormatter(fmt)
fh.setFormatter(fmt)
# 给记录器添加处理器
logger.addHandler(ch)
logger.addHandler(fh)
# 捕获日志信息
logger.info("the message info")
logger.error("the message of error")
将上面代码封装成一个类,方便使用
import logging
class Logger:
"""
将日志信息打印到控制台和记录到文件的操作封装成一个类
"""
def __init__(self, name: str, console_handler_level: str = logging.DEBUG,
fmt: str = '%(asctime)s: %(levelname)s: %(name)s: %(filename)s: %(message)s'):
"""
默认会添加一个等级为 'DEBUG' 的 Handler 对象到 Logger 对象
:param name: handler 的名称
:param console_handler_level: 设置 StreamHandler 的等级
:param fmt: 日志消息的显示格式
"""
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.DEBUG)
self.fmt = logging.Formatter(fmt)
self.set_console_handler(console_handler_level)
def set_console_handler(self, console_handler_level: str = logging.DEBUG) -> None:
ch = logging.StreamHandler()
ch.setLevel(console_handler_level)
ch.setFormatter(self.fmt)
self.logger.addHandler(ch)
def set_file_handler(self, filename: str, mode: str = 'a', file_handler_level: str = logging.INFO) -> None:
fh = logging.FileHandler(filename, mode=mode, encoding='utf-8')
fh.setLevel(file_handler_level)
fh.setFormatter(self.fmt)
self.logger.addHandler(fh)
def debug(self, msg):
self.logger.debug(msg)
def info(self, msg):
self.logger.info(msg)
def warning(self, msg):
self.logger.warning(msg)
def error(self, msg):
self.logger.error(msg)
def critical(self, msg):
self.logger.critical(msg)
日志(logging模块)的更多相关文章
- day18包的使用与日志(logging)模块
包的使用与日志(logging)模块1. 什么是包 包就是一个包含有__init__.py文件的文件夹 包本质就是一种模块,即包是用包导入使用的,包内部包含的文件也都是用来被导入使用2 为 ...
- python中日志logging模块的性能及多进程详解
python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...
- python 的日志logging模块学习
1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message') logging.info('This is info messa ...
- Python之日志 logging模块
关于logging模块的日志功能 典型的日志记录的步骤是这样的: 创建logger 创建handler 定义formatter 给handler添加formatter 给logger添加handler ...
- python 的日志logging模块
1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message')logging.info('This is info messag ...
- Python日志(logging)模块,shelve,sys模块
菜鸟学python第十七天 1.logging 模块 logging模块即日志记录模块 用途:用来记录日志 为什么要记录日志: 为了日后复查,提取有用信息 如何记录文件 直接打开文件,往里写东西 直接 ...
- python的日志logging模块性能以及多进程
写在前面: 日志是记录操作的一种好方式.但是日志,基本都是基于文件的,也就是要写到磁盘上的.这时候,磁盘将会成为一个性能瓶颈.对于普通的服务器硬盘(机械磁盘,非固态硬盘),python日志的性能瓶颈是 ...
- python+Appium自动化:日志logging模块
日志级别 debug.info.warn.error.critical五个级别 logging模块构成(四部分) logger(记录器,用于日志采集) Handler(处理器,将日志记录发送到合适的路 ...
- Python中日志logging模块
# coding:utf-8 import logging import os import time class Logger(object): def __init__(self): # 创建一个 ...
- Python的日志记录-logging模块的使用
一.日志 1.1什么是日志 日志是跟踪软件运行时所发生的事件的一种方法,软件开发者在代码中调用日志函数,表明发生了特定的事件,事件由描述性消息描述,同时还包含事件的重要性,重要性也称为级别或严重性. ...
随机推荐
- Nvidia Triton使用教程:从青铜到王者
1 相关预备知识 模型:包含了大量参数的一个网络(参数+结构),体积10MB-10GB不等 模型格式:相同的模型可以有不同的存储格式(可类比音视频文件),目前主流有torch.tf.onnx和trt, ...
- SpringMVC乱码解决
解决需要四个步骤:1.jsp页面编码 2.tomcat server.xml编码 3.使用filter对编码进行过滤 4.数据库编码设置 说明:四个地方的编码需要一致:本文使用gbk 1.js ...
- Spring Boot 3.0.0 M3、2.7.0发布,2.5.x将停止维护
昨晚(5月19日),Spring Boot官方发布了一系列Spring Boot的版本更新,其中包括: Spring Boot 3.0.0-M3 Spring Boot 2.7.0 Spring Bo ...
- 安装Net-Tools到CentOS(YUM)
Net-Tools是一个Linux系统中基本的网络工具集,其集成了常用的网络管理命令"ifconfig.netstat.arp.route等". 运行环境 系统版本:CentOS ...
- 关键路径 p3 清华复试上机题
关键路径 p3 清华复试上机题 题目描述 小H为了完成一篇论文,一共要完成n个实验.其中第i个实验需要a[i]的时问去完成.小H可以同时进行若干实验,但存在一些实验,只有当它的若干前置实验完成时,才能 ...
- Chrome自带功能实现网页截图
更新记录 本文迁移自Panda666原博客,原发布时间:2021年6月28日. 很简单,按下Ctrl+Shift+P,打开命令行窗口,如下图所示. 输入命令. Capture full size sc ...
- 详解PHP如何实现斐波那契数列的简单实例
文章来自:有解网 http://www.youjieweb.com/original/index/articleId/64.html 使用场景: 面试 本文讲的是如何用php实现PHP实现斐波那契数列 ...
- 对互斥事件和条件概率的相互理解《考研概率论学习之我见》 -by zobol
1.从条件概率来定义互斥和对立事件 2.互斥事件是独立事件吗? 3.每个样本点都可以看作是互斥事件,来重新看待条件概率 一.从条件概率来定义互斥和对立事件 根据古典概率-条件概率的定义,当在" ...
- SpringBoot整合SpringSecurityOauth2实现鉴权-动态权限
写在前面 思考:为什么需要鉴权呢? 系统开发好上线后,API接口会暴露在互联网上会存在一定的安全风险,例如:爬虫.恶意访问等.因此,我们需要对非开放API接口进行用户鉴权,鉴权通过之后再允许调用. 准 ...
- Node.js精进(3)——流
在 JavaScript 中,一般只处理字符串层面的数据,但是在 Node.js 中,需要处理网络.文件等二进制数据. 由此,引入了Buffer和Stream的概念,两者都是字节层面的操作. Buff ...