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(格式器):设置日志记录的输出格式;

下面说明这几个组件之间的联系及处理顺序:

  1. 首先通过 getLogger() 方法一个指定名称的 Logger实例的引用,如果没提供名称,则返回 rootlogger = getLogger(name)
  2. 为 Logger 实例设置捕获信息的等级,默认等级为 WARNING,logger.setLevel('INFO')
  3. logger 通过调用 debug()、info()、warning()、error()、critical() 这些方法来捕获日志信息;Logger 只暴露接口供程序员调用,用来捕获日志信息,而不处理信息;只捕获大于等于其自身等级的信息;
  4. 如果 logger 捕获了日志信息,则将日志信息传递给 Handler 进行处理;
  5. 每个 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模块)的更多相关文章

  1. day18包的使用与日志(logging)模块

    包的使用与日志(logging)模块1. 什么是包    包就是一个包含有__init__.py文件的文件夹    包本质就是一种模块,即包是用包导入使用的,包内部包含的文件也都是用来被导入使用2 为 ...

  2. python中日志logging模块的性能及多进程详解

    python中日志logging模块的性能及多进程详解 使用Python来写后台任务时,时常需要使用输出日志来记录程序运行的状态,并在发生错误时将错误的详细信息保存下来,以别调试和分析.Python的 ...

  3. python 的日志logging模块学习

    1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message') logging.info('This is info messa ...

  4. Python之日志 logging模块

    关于logging模块的日志功能 典型的日志记录的步骤是这样的: 创建logger 创建handler 定义formatter 给handler添加formatter 给logger添加handler ...

  5. python 的日志logging模块

    1.简单的将日志打印到屏幕 import logging logging.debug('This is debug message')logging.info('This is info messag ...

  6. Python日志(logging)模块,shelve,sys模块

    菜鸟学python第十七天 1.logging 模块 logging模块即日志记录模块 用途:用来记录日志 为什么要记录日志: 为了日后复查,提取有用信息 如何记录文件 直接打开文件,往里写东西 直接 ...

  7. python的日志logging模块性能以及多进程

    写在前面: 日志是记录操作的一种好方式.但是日志,基本都是基于文件的,也就是要写到磁盘上的.这时候,磁盘将会成为一个性能瓶颈.对于普通的服务器硬盘(机械磁盘,非固态硬盘),python日志的性能瓶颈是 ...

  8. python+Appium自动化:日志logging模块

    日志级别 debug.info.warn.error.critical五个级别 logging模块构成(四部分) logger(记录器,用于日志采集) Handler(处理器,将日志记录发送到合适的路 ...

  9. Python中日志logging模块

    # coding:utf-8 import logging import os import time class Logger(object): def __init__(self): # 创建一个 ...

  10. Python的日志记录-logging模块的使用

    一.日志 1.1什么是日志 日志是跟踪软件运行时所发生的事件的一种方法,软件开发者在代码中调用日志函数,表明发生了特定的事件,事件由描述性消息描述,同时还包含事件的重要性,重要性也称为级别或严重性. ...

随机推荐

  1. Ajax——Get请求

    Get.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  2. 数据库与MySQL的下载使用

    目录 数据存储演变史 数据库应用发展史 数据库本质 数据库分类 关系型数据库 非关系型数据库 SQL与NoSQL MySQL简介 版本问题 下载使用 目录结构 基本使用 简单使用 系统服务 修改密码 ...

  3. python之数据类型的内置方法(set、tuple、dict)与简单认识垃圾回收机制

    目录 字典的内置方法 类型转换 字典取值 修改值 计算字典长度 成员运算 删除元素 获取元素 更新字典 快速生成字典 setdefault()方法 元组的内置方法 类型转换 索引与切片操作 统计长度 ...

  4. Vben Admin 源码学习:状态管理-错误日志

    0x00 前言 本文将对 Vue-Vben-Admin 的状态管理实现源码进行分析解读,耐心读完,相信您一定会有所收获! 0x01 errorLog.ts 错误日志 文件 src\store\modu ...

  5. Spring Ioc源码分析系列--容器实例化Bean的四种方法

    Spring Ioc源码分析系列--实例化Bean的几种方法 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分 ...

  6. split(),strip,split("/")[-1] 和 split("/",-1)的区别

    Python中split()函数,通常用于将字符串切片并转换为列表. 一.函数说明: split():语法: str.split(str="",num=string.count(s ...

  7. JavaScript之创建八个对象过520

    马上又到了一年一度的520了,程序猿们赶紧创建对象过520吧!!! JavaScript创建对象的几种方式: 一:字面量方式: var obj = {name: '程序猿'}; 二:通过new操作符: ...

  8. Linux服务器启动jstatd服务

    Linux服务器启动jstatd服务 1.查找jdk所在目录 2.在jdk的bin目录下创建文件jstatd.all.policy touch jstatd.all.policy 3.写入安全配置 g ...

  9. go-zero微服务实战系列(四、CRUD热热身)

    上一篇文章我们把整个项目的架子搭建完成,服务在本地也已经能运行起来了,顺利成章的接下来我们就应该开始写业务逻辑代码了,但是单纯的写业务逻辑代码是比较枯燥的,业务逻辑的代码我会不断地补充到 lerbon ...

  10. 【Spring】事务的执行原理(三)

    事务的回滚 如果获取事务属性不为空,并且抛出的异常是RuntimeException或者Error类型,调用事务管理器中的rollback方法进行回滚 如果事务属性为空或者抛出的异常不是Runtime ...