Python学习系列 -初探标准库之logging库

系列文章目录

第一章 初始 Python
第二章 认识 Python 变量、类型、运算符
第三章 认识 条件分支、循环结构
第四章 认识 Python的五种数据结构
第五章 认识 Python 函数、模块
第六章 认识面向对象三大特性
第七章 初探标准库之os库
第八章 初探标准库之pathlib库
第九章 初探标准库之Shutil库
第十章 初探标准库之re库
第十一章 初探标准库之time和datetime库
第十二章 初探标准库之configparser和第三方pyyaml库
第十三章 初探标准库之logging库


文章目录

  • 系列文章目录
      • 文章开篇
      • 日志的作用
      • 日志的等级
      • 日志的消息格式
      • logging四大组件
      • Logger类
      • Handler类
      • Formatter类
      • Filter类
      • 真实代码封装
      • 总结


文章开篇

Python的魅力,犹如星河璀璨,无尽无边;人生苦短、我用Python!


日志的作用

日志捕捉是软件运行时追踪内部事件的重要工具,对于错误排查和系统运维都至关重要;
通过在代码中嵌入日志记录方法,开发人员可以捕获并记录难以察觉的事件,并提供事件的背景信息;
此外,日志还标记事件的重要性或严重性级别,帮助开发人员快速识别关键事件,从而提高软件的健壮性和用户体验;


日志的等级


在这里插入图片描述

级别应用场景
DEBUG调试信息,通常在诊断问题的时候用
INFO普通信息,确认程序在按照预期运行
WARNING警告信息,程序运行时出现了意外情况或预示可能出现的问题,但程序仍会继续运行
ERROR错误信息,程序运行中出现了异常错误,程序某些功能无法执行
CRITICAL危险信息,程序运行中出现了严重的错误,导致程序无法继续运行

使用不同的日志级别进行记录日志信息

import logging# 默认打印到控制台
logging.basicConfig(level=logging.DEBUG)
# 指定记录到日志文件(后续详解)
# logging.basicConfig(filename="test.log", level=logging.DEBUG)logging.debug("调试信息")       # DEBUG:root:调试信息
logging.info("普通信息")        # INFO:root:普通信息
logging.warning("警告信息")     # WARNING:root:警告信息
logging.error("错误信息")       # ERROR:root:错误信息
logging.critical("危险信息")    # CRITICAL:root:危险信息

日志的消息格式

格式说明
%(message)s日志消息内容
%(asctime)s创建日志记录可读时间
%(funcName)s日志调用所在函数名
%(levelname)s日志级别
%(levelno)s消息级别数字
%(lineno)s日志调用所在源码行号
%(module)s模块(filename名字部分)
%(process)进程ID
%(thread)s线程ID
%(processName)s进程名
%(threadName)s线程名

logging四大组件

在这里插入图片描述

组件名称对应类名功能描述
日志器Logger提供了应用程序可一直调用的接口
处理器Handler将logger创建的日志记录发送到合适的目的地输出
过滤器Filter提供了更细颗粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录
格式器Formatter决定日志记录的最终输出格式

Logger类

Logger主要做三件事情:

  • 提供日志记录方法给应用程序;
  • 根据日志的严重等级或过滤器决定处理哪些日志;
  • 将日志消息发送给所有处理器对象;

常用的配置方法说明
Logger.setLevel()为logger对象设置日志器处理的最低日志级别
Logger.addHandler()为logger对象添加一个Handler处理器对象
Logger.removeHandler()为logger对象移除一个Handler处理器对象
Logger.addFilter()为logger对象添加一个Filter过滤器对象
Logger.removeFilter()为logger对象移除一个Filter过滤器对象

关于Logger.setLevel()方法的说明:
在内置的级别中,DEBUG最低,CRITICAL最高
如setLevel(logging.INFO)只会处理INFO及以上级别的日志,而忽略DEBUG级别的消息;

创建日志记录的方法说明
Logger.debug()创建一个调试级别的日志记录
Logger.info()创建一个普通级别的日志记录
Logger.warning()创建一个警告级别的日志记录
Logger.error()创建一个错误级别的日志记录
Logger.critical()创建一个危险级别的日志记录
Logger.exception()创建一个异常级别的日志记录
Logger.log()需要获取一个明确的日志级别参数来创建一个日志记录

获取Logger对象的方式:

  • 通过Logger类的实例化方法创建一个Logger类的实例;
  • 通过logging模块的getLogger()方法获取;

通常我们都是使用第二种方式,logging.getLogger()方法有一个可选参数name
该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为root
相同的name参数多次调用getLogger()方法,返回同一个logger对象的引用;

import logging# 默认打印到控制台
logging.basicConfig(level=logging.DEBUG)log = logging.getLogger("zhangsan")log.debug("调试信息")       # DEBUG:root:调试信息
log.info("普通信息")        # INFO:root:普通信息
log.warning("警告信息")     # WARNING:root:警告信息
log.error("错误信息")       # ERROR:root:错误信息
log.critical("危险信息")    # CRITICAL:root:危险信息

Handler类

Handler对象的作用是根据日志消息的级别将其分发到指定位置,如文件、网络或邮件等。
Logger对象可通过addHandler()方法添加多个handler以满足不同的日志需求
将所有严重级别的日志记录到文件;
将严重级别为error及以上的日志输出到标准输出;
将严重级别为critical的日志发送到邮件地址;
上述场景需要多个handlers,每个负责处理特定级别的日志并发送到特定位置


开发人员通常只需关注handler中的少数方法
对于使用内置handler对象的应用开发人员,最关键的是配置方法,如设置日志级别、格式和输出目标等;
其他方法对于大多数应用场景来说可能并不重要;


Handler常用配置方法说明
Handler.setLevel()为handler对象设置最低严重级别的日志消息
Handler.setFormatter()为handler对象设置一个Formatter格式器对象
Handler.addFilter()为handler对象添加一个Filter过滤器对象
Handler.removeFilter()为handler对象移除一个Filter过滤器对象

因为Handler是基类,仅定义了通用接口和默认行为;
应用程序代码应避免直接实例化和使用Handler实例;
开发人员应使用其子类或覆盖默认行为来满足具体需求;


常用的Handler对象说明
logging.StramHandler将日志消息输出到Stream,如std.out、std.err或任何file-like对象
logging.FileHandler将日志消息发送到磁盘文件,默认情况下文件会无限增长
logging.handlers.RotaingFileHandler将日志消息发送到磁盘文件,并支持日志文件按大小切割
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('my_logger')
logger.setLevel(logging.DEBUG)  # 设置日志级别# 创建一个handler,用于将日志信息打印到控制台
handler = logging.StreamHandler()# 给logger添加handler
logger.addHandler(handler)# 记录一些日志
logger.debug('这是一个调试信息...')     # 这是一个调试信息...
logger.info('这是一个普通信息...')      # 这是一个普通信息...
logger.warning('这是一个警告信息...')   # 这是一个警告信息...
logger.error('这是一个错误信息...')     # 这是一个错误信息...
logger.critical('这是一个危险信息...')  # 这是一个危险信息...

Formatter类

Formater对象用于配置日志信息的最终顺序、结构和内容
与logging.Handler基类不同的是,Formatter类可以直接实例化
对于特殊的输出需求,可以根据需求创建Formatter的子类来实现;

Formatter类的构造方法定义如下:

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

该构造方法有三个可选参数:

  • fmt用于定义消息格式,默认为原始消息;
  • datefmt设置日期格式,默认是"%Y-%m-%d %H:%M:%S";
  • style在Python 3.2引入,可选’%', ‘{‘或’$’,默认为 ‘%’;

import logging# 创建一个logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)  # 设置日志级别# 创建一个handler,用于将日志信息打印到控制台
handler = logging.StreamHandler()# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)# 给logger添加handler
logger.addHandler(handler)# 记录一些日志
logger.debug('这是一个调试信息...')     # 2024-02-27 14:11:17,513 - my_logger - DEBUG - 这是一个调试信息...
logger.info('这是一个普通信息...')      # 2024-02-27 14:11:17,513 - my_logger - INFO - 这是一个普通信息...
logger.warning('这是一个警告信息...')   # 2024-02-27 14:11:17,513 - my_logger - WARNING - 这是一个警告信息...
logger.error('这是一个错误信息...')     # 2024-02-27 14:11:17,513 - my_logger - ERROR - 这是一个错误信息...
logger.critical('这是一个危险信息...')  # 2024-02-27 14:11:17,513 - my_logger - CRITICAL - 这是一个危险信息...

Filter类

Filter是logging模块中一个基类
用于Handler和Logger实现比日志级别更细粒度和复杂的过滤功能,它允许根据logger的层级来筛选日志事件;
filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤


class logging.Filter(name='')filter(record)

Filter类根据传入的name参数值来过滤日志记录
name设置为’A.B’时,它只允许logger名称以’A.B’为前缀(包括’A.B’本身和它的任何子logger)的日志记录通过过滤;
对于不符合这一前缀规则的logger名称,如’A.BB’和’B.A.B’,它们产生的日志记录将被过滤掉
如果name参数值为空字符串,则该过滤器允许所有日志事件通过,不进行任何名称相关的过滤

import loggingclass MyFilter(logging.Filter):def __init__(self, name='', key_word='测试'):super().__init__(name)# 设置filter的名字,虽然这里使用了,但实际上filter的名字通常不用于过滤决策self.name = name# 设置过滤条件self.key_word = key_wordself.levelno = logging.INFOself.logger_name = 'my_app'def filter(self, record):# 如果日志信息中以“测试”开头,则忽略if record.getMessage().startswith(self.key_word):return False# 如果record的levelno和logger_name与设置的条件匹配,则返回True,否则返回Falsereturn record.levelno == self.levelno and record.name == self.logger_name# 创建一个logger
logger = logging.getLogger('my_app')
logger.setLevel(logging.INFO)# 创建一个handler,用于写入日志文件
handler = logging.StreamHandler()# 创建一个自定义的filter
filter_instance = MyFilter()# 添加filter到handler
handler.addFilter(filter_instance)# 定义handler的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)# 给logger添加handler
logger.addHandler(handler)# 上述过滤器对象,设置仅记录INFO等级
logger.info('这是一个普通信息...')          # 2024-02-27 14:11:17,513 - my_logger - INFO - 这是一个普通信息...
logger.info('测试是否能够捕捉info信息...')   # 不会被记录

真实代码封装

真实应用案例封装,可直接拿去运用到实际开发项目中;
Log类是通过Python的内置模块logging模块封装的工具类;
代码释义如下:

  • 单例模式,保证其他模块导入时不会重新实例化
  • 按天生成,每天生成一个日志文件,不会让日志过大或过小
  • 格式美化,展示日期时间、模块名称、行号、日志等级
  • 输出打印
  • 文件记录

import logging
import datetime
import os
import time
import traceback  # 回溯模块# 通过装饰器完成单例模式
def singleton(cls):# 使用字典存储类对象的实例instances = {}def _singleton(*args, **kwargs):if cls not in instances:# 如果类没有被创建过,那就new个新对象并存储到字典中instances[cls] = cls(*args, **kwargs)return instances[cls]return _singletonclass Log(object):def __init__(self):'''创建日志器'''self.log = logging.getLogger()# 创建handlers之前,将已经存在的移除,再重新创建,可以防止日志重复while self.log.hasHandlers():for handler in self.log.handlers:self.log.removeHandler(handler)# 设置日志信息等级self.log.setLevel(level='INFO')def console_handle(self):'''创建控制台处理器'''self.console_handler = logging.StreamHandler()# 设置格式器self.console_handler.setFormatter(self.get_formatter()[0])# 返回作用给日志器使用return self.console_handlerdef file_handle(self):'''创建文件处理器'''# 当前文件的绝对路径去除当前文件所在目录加上日志文件存放目录logfile_path = os.path.dirname(os.path.dirname(__file__)) + "/logs"current_date = datetime.datetime.now().strftime("%Y-%m-%d")logfile_name = logfile_path + '/执行日志 ' + current_date + '.log'try:# 判断是否已经生成日志文件存放目录if not os.path.exists(logfile_path):os.makedirs(logfile_path)# 判断是否已经生成今天的日志文件if not os.path.exists(logfile_name):open(logfile_name, mode='a')except OSError:passself.file_handler = logging.FileHandler(filename=logfile_name, mode='a', encoding='utf-8')# 设置格式器self.file_handler.setFormatter(self.get_formatter()[1])# 返回作用给日志器使用return self.file_handlerdef get_formatter(self):'''格式器'''self.console_fmt = logging.Formatter(fmt='%(asctime)s --> %(filename)-30s [line:%(lineno)-3d] --> %(levelname)-5s --> %(message)s')self.file_fmt = logging.Formatter(fmt='%(asctime)s --> %(filename)-30s [line:%(lineno)-3d] --> %(levelname)-5s --> %(message)s')# 返回作用给控制台处理器、文件处理器使用return self.console_fmt, self.file_fmt@singletondef get_log(self):'''日志器添加处理器'''self.log.addHandler(self.console_handle())self.log.addHandler(self.file_handle())return self.loglog = Log().get_log()if __name__ == '__main__':log = Log().get_log()log.info('提示信息')log.error('错误信息')try:int('hello world')except ValueError as e:print('在此处进行异常的处理')# 将错误信息写入日志文件log.error(traceback.format_exc())time.sleep(3)print('测试是否被异常中断')# 日志文件内容如下:
# 2024-02-27 14:40:10,923 --> LoggerCfg.py  [line:84 ] --> INFO  --> 提示信息
# 2024-02-27 14:40:10,923 --> LoggerCfg.py  [line:85 ] --> ERROR --> 错误信息
# 2024-02-27 14:40:10,923 --> LoggerCfg.py  [line:91 ] --> ERROR --> Traceback (most recent call last):
#  File "/Users/yangkai/PythonWorkspace/第49课:第三方库/CASE11:Logging/LoggerCfg.py", line 87, in <module>
#    int('hello world')
# ValueError: invalid literal for int() with base 10: 'hello world'

总结

Python的logging模块是Python标准库中的一个强大的日志记录工具;
它支持多种日志级别、灵活的配置选项和丰富的输出目标,如文件、控制台等;
日志记录是记录应用运行时状态和事件的关键方法,对于问题诊断、流程追踪、错误发现及性能优化具有重要意义;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/496582.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

卷积神经网络介绍

卷积神经网络(Convolutional Neural Networks&#xff0c;CNN) 网络的组件&#xff1a;卷积层&#xff0c;池化层&#xff0c;激活层和全连接层。 CNN主要由以下层构造而成&#xff1a; 卷积层&#xff1a;Convolutional layer&#xff08;CONV&#xff09;池化层&#xff1a…

如何在windows系统部署Lychee网站,并结合内网穿透打造个人云图床

文章目录 1.前言2. Lychee网站搭建2.1. Lychee下载和安装2.2 Lychee网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 图床作为图片集中存放的服务网站&#xff0c;可以看做是云存储的一部分&#xff0c;既可…

批量自动加好友,轻松拓展微信人脉圈子

在当今社交化的时代&#xff0c;拓展社交圈子已经成为许多人努力追求的目标。而微信作为中国人群中最主流的社交工具之一&#xff0c;更是成为人们拓展社交圈子的重要场所。在这样的背景下&#xff0c;有没有一种简单而高效的方式来扩大微信人脉圈子呢&#xff1f;答案是肯定的…

【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)

目录 1、锁的策略 1.1、乐观锁和悲观锁 1.2、轻量级锁和重量级锁 1.3、自旋锁和挂起等待锁 1.4、普通互斥锁和读写锁 1.5、公平锁和非公平锁 1.6、可重入锁和不可重入锁 2、synchronized 内部的升级与优化过程 2.1、锁的升级/膨胀 2.1.1、偏向锁阶段 2.1.2、轻量级锁…

RunnerGo UI自动化测试脚本如何配置

RunnerGo提供从API管理到API性能再到可视化的API自动化、UI自动化测试功能模块&#xff0c;覆盖了整个产品测试周期。 RunnerGo UI自动化基于Selenium浏览器自动化方案构建&#xff0c;内嵌高度可复用的测试脚本&#xff0c;测试团队无需复杂的代码编写即可开展低代码的自动化…

第十四天-网络爬虫基础

1.什么是爬虫 1.爬虫&#xff08;又被称为网页蜘蛛&#xff0c;网络机器人&#xff09;&#xff0c;是按照一定规则&#xff0c;自动的抓取万维网中的程序或者脚本&#xff0c;是搜索引擎的重要组成&#xff1b;比如&#xff1a;百度、 2.爬虫应用&#xff1a;1.搜索引擎&…

【web APIs】3、(学习笔记)有案例!

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、概念其他事件页面加载事件元素滚动事件页面尺寸事件 元素尺寸与位置 二、案例举例电梯导航 前言 掌握阻止事件冒泡的方法理解事件委托的实现原理 一、概念…

✈️ 运输行业有哪些令人无法接受的网络安全事件?

Positive Technologies 专家举例说明 去年 9 月&#xff0c;Leonardo 订票系统遭到大规模 DDoS 攻击&#xff0c;导致全球网络中断&#xff0c;Aeroflot 航班难以办理登机手续。这导致谢列梅捷沃机场多趟航班延误起飞。 这只是 Positive Technologies 专家在其 2023 年交通领…

Golang使用Swag搭建api文档

1. 简介 Gin是Golang目前最为常用的Web框架之一。 公司项目验收需要API接口设计说明书&#xff08;Golang后端服务基于Gin框架编写&#xff09;&#xff0c;编写任务自然就落到了我们研发人员身上。 项目经理提供了文档模板&#xff0c;让我们参考模板来手动编写&#xff0c;要…

【React源码 - 调度任务循环EventLoop】

我们知道在React中有4个核心包、2个关键循环。而React正是在这4个核心包中运行&#xff0c;从输入到输出渲染到web端&#xff0c;主要流程可简单分为一下4步&#xff1a;如下图&#xff0c;本文主要是介绍两大循环中的任务调度循环。 4个核心包&#xff1a; react&#xff1a;…

docker启动nginx,修改index.html文件默认网页返回没有生效

先跟着网上的方法做 # 进入目录 [rootkubesphere_1 html]# docker exec -it mynginx /bin/bash rootc57f1c95ab1b:/etc/nginx# vi nginx.conf # 先下载编辑工具 rootc57f1c95ab1b:/etc/nginx# apt-get update rootc57f1c95ab1b:/etc/nginx# apt-get install vim# 增加下面 —…

Dockerfile(4) - RUN 指令详解

RUN 运行命令 shell 形式 命令在 shell 中运行Linux 上默认为 /bin/sh -cWindows 上 cmd /S /C RUN <command> exec 形式 RUN ["executable", "param1", "param2"] 必须双引号&#xff0c;不能是单引号 两种写法的实际栗子 RUN …