Python自带日志库实现springboot彩色效果

news2024/11/15 17:54:19

整体目标

在这里插入图片描述

涉及的库均为Python3自带库实现

  • logging
  • sys
  • enum

终端显示彩色基本原理参考👉Terminal里的颜色的那些事

Python打印日志可以直接借用logging自带的库实现,但是默认的打印实在太丑了,长下面这样

在这里插入图片描述

这只是一条日志看着还好比较清爽,如果多了之后可想而知,大片红色看着由多么糟糕,借鉴SpringBoot的处理怎么做到SpringBoot那样的彩色日志输出呢?

在这里插入图片描述

这里突然想起来,Java自带的日志框架(JUL)打印也是一片红色,可能原生的东西都比较呆正。

日志框架的组成

日志框架无论哪种语言基本都是遵循一样的做法,包括以下组件:

  • Logger:日志记录器,用于记录打印日志,我们操作的就是这个对象
  • Handler:处理器,有些也叫Appender,就是实际处理日志记录的东西,比如说我们生成一条日志字符串,这个字符串是输出到控制台,还是输出到文件呢?或者说两者都输出呢?这就是处理器做的事情,如果存在多个处理器还可以重复输出。
  • Formatter:格式化器,有些框架也叫Layout,就是格式化信息的,比如我们看到上面工工整整的时间,日志级别,就是我们定义好的格式,交给他处理。

正常打印一条日志,都是由日志记录器开始,日志记录器存在属性Handler处理器,处理器Handler存在属性Formatter。因此我们需要操作的对象就是Formatter

import logging  
  
if __name__ == '__main__':  
    # Logger Handler Formatter 三者之间的关系,相互链接建立联系  
    formatter = logging.Formatter(logging.BASIC_FORMAT)  
    handler = logging.StreamHandler()  
      
    handler.setFormatter(formatter)  
    logging.getLogger().addHandler(handler)

因此我们如果要自定义处理器或者自定义格式化器,都是从上面的setFormatter和addHandler入手的。

如何自定义这些组件? 答案是继承,Python中我们无法实现接口,但是可以继承基类,只要是儿子,自然也就是处理器,或者格式化器。

class CustomFormatter(logging.Formatter):  
	# 重写父类的方法,再调用父类,相当于增强方法
    def format(self, record):   
	    # 这里就可以处理记录record的了
        s = super().format(record)  
        return s

我们的基本思路就是拿到需要格式化的数据,%(asctime)s时间字符串,%(levelname)s等级字符串这些,拿到这些数据那就可以进行彩色处理了。

终端彩色显示

ANSI转义序列(ANSI escape sequences)是一种带内信号的转义序列标准,用于控制视频文本终端上的光标位置、颜色和其他选项。在文本中嵌入确定的字节序列,大部分以ESC转义字符和"["字符开始,终端会把这些字节序列解释为相应的指令,而不是普通的字符编码。

大体原理就是类似\r代表回到开头,\n代表换行这种,具有一定的转义含义的东西,在终端不同的转义含义就可以控制输出的字体颜色,背景颜色,字体加粗,划线等等。

基本格式为:

\033[XXXm

其中\033[以及后面的m都是固定的,只有XXX代表不同含义,分别由;分割,比如下面的例子

print("\033[31;9;3mHello Python\033[m")

其中31表示前景色(字体颜色)为红色,9表示划除线,3表示斜体

效果图
在这里插入图片描述

注意:并不是说第一个数字一定要控制颜色,也可以完全没有颜色控制的!

具体的ANSI转义表参考复杂正规版

简单的网上搜一下就好,就是说每个数字代表什么含义的码表,比如你想要粗体应该是数字1。

我们的目的是颜色,标准颜色的数字是30~37分别如下表示:

颜色前景色代码
黑色30
红色31
绿色32
黄色33
蓝色34
品红35
青色36
白色37
print("\033[31mINFO\033[m")  
print("\033[32mINFO\033[m")  
print("\033[33mINFO\033[m")  
print("\033[34mINFO\033[m")  
print("\033[35mINFO\033[m")  
print("\033[36mINFO\033[m")  
print("\033[37mINFO\033[m")

效果图
在这里插入图片描述

所以我们只需要获取到指定字符串然后包裹封装就可以了,问题是怎么获取呢?

完整实现

from enum import Enum
import logging

# 枚举类用来记录颜色
class Color(Enum):  
    BLACK = 30  
    RED = 31  
    GREEN = 32  
    YELLOW = 33  
    BLUE = 34  
    CYAN = 36 
    WHITE = 37 
    DEFAULT = 39 

# ANSI转义颜色包裹需要颜色显示的字符串
def color_text(text: str, color: Color) -> str:  
    return "\033[{}m{}\033[0m".format(str(color.value), text)


# 自定义格式化器继承Formatter,在format格式化之前拿到需要变化的字段字符串,这里主要就是日志级别和记录器名称
class CustomFormatter(logging.Formatter):  
    def format(self, record):  
        if record.levelname == "INFO":  
            level_name_color = Color.GREEN  
        elif record.levelname == "ERROR":  
            level_name_color = Color.RED  
        elif record.levelname == "WARNING":  
            level_name_color = Color.YELLOW  
        else:  
            level_name_color = Color.DEFAULT  
  
        record.levelname = color_text(record.levelname, level_name_color)  
        record.name = color_text(record.name, Color.CYAN)  
        s = super().format(record)  
        return s
    
# 设置自定义格式化器,这里封装一个方法用来获取日志记录器,正好在这里添加格式化器,控制台输出处理器Handler默认是StreamHandler
def getLogger(name: str = __name__):  
    logger = logging.getLogger(name)  
  
    handler = logging.StreamHandler()  
  
    handler.setLevel("DEBUG")  
    format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"  
    handler.setFormatter(CustomFormatter(fmt=format))  
  
    logger.addHandler(handler)  
    logger.propagate = 0  
    return logger

效果图
在这里插入图片描述

注意:这里需要配置记录器的日志级别,记录器的日志级别向下传递给处理器,所以其实处理器本质不设置日志级别也是可以的,由记录器传递。

上面还有个关键问题,为什么整体颜色还是红色?

答案是对于终端的输出分为stdout和stderr,而StreamHandler.stream输出流默认输出为stderr,因为我们还需要加一行关键的代码。

getLogger方法中添加

handler.stream = sys.stdout

最终效果图
在这里插入图片描述

Note:

  • 为了更接近SpringBoot效果,对格式化内容做了调整
  • 日志级别其实最高也就WARNING共7个字符,但是由于加了转义序列,实际长度并不是7,因此如果太小则会出现对不齐的情况,这里采用%(levelname)18s占位18个字符右对齐。

格式化标准:

format = "%(asctime)s - %(levelname)18s - [%(name)15s] - %(message)s"

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VUE+Tailwind网页开发

从nodejs官网下载安装包并安装&#xff1a;https://nodejs.org/zh-cn 参考vue官网步骤配置项目&#xff1a;https://cn.vuejs.org/guide/quick-start.html $ npm create vuelatest $ cd <your-project-name> $ npm install 参考&#xff0c;安装vue-router:安装 | Vue…

【CanMV K230】矩形检测

【CanMV K230】矩形检测 什么是 矩形检测矩形检测应用领域1.目标检测2.自动驾驶3.医学图像处理4.智能零售5.图像识别6.计算机视觉 K230应用相关函数官方例程 本篇内容&#xff1a; 什么是 矩形检测矩形检测应用领域K230应用&#xff08;包含相应函数及例程&#xff09; B站视频…

【有啥问啥】HashHop在LTM-2-mini中的应用:解锁长期记忆模型的新纪元

HashHop在LTM-2-mini中的应用&#xff1a;解锁长期记忆模型的新纪元 引言 随着AI技术的飞速发展&#xff0c;模型在处理复杂任务和数据时所需的上下文窗口大小也在不断扩展。深度学习模型在处理超长上下文时&#xff0c;往往面临着计算资源消耗高、上下文丢失等问题。近期&am…

通信工程学习:什么是IFMP(Ipsilon流管理协议)

IFMP&#xff1a;Ipsilon流管理协议 IFMP&#xff08;Ipsilon Flow Management Protocol&#xff09;&#xff0c;即Ipsilon流量管理协议&#xff0c;是一种用于网络流量管理的协议。它主要用于IP交换机、IP交换网关或IP主机中&#xff0c;通过控制数据传送&#xff0c;将现有网…

【H2O2|全栈】更多关于HTML(1)HTML进阶(一)

目录 HTML进阶知识 前言 准备工作 标签的扩展&#xff08;一&#xff09; 本文中的标签在什么位置使用&#xff1f; title标签 meta标签 name viewport referrer http-equiv charset content link标签 实际案例 可视部分 代码分析 其他标签 base标签 styl…

《论企业集成平台的技术与应用》写作框架,软考高级系统架构设计师

论文真题 企业集成平台是一个支持复杂信息环境下信息系统开发、集成和协同运行的软件支撑环境。它基于各种企业经营业务的信息特征,在异构分布环境(操作系统、网络、数据库)下为应用提供一致的信息访问和交互手段,对其上运行的应用进行管理,为应用提供服务,并支持企业信…

数论技巧——使用线性筛法去求1~n之间欧拉函数的和

本节是数论中的重要内容&#xff0c;也是算法竞赛中的常考点&#xff0c;初学者理解起来可能有些困难&#xff0c;需要多多体会 给定一个正整数 n&#xff0c;求 1∼n 中每个数的欧拉函数之和。 欧拉函数的定义&#xff1a;1~n中与n互质的数的个数被称为欧拉函数,记作φ(n) 欧…

操作系统 ---- 进程的概念、组成、特征

学习路线&#xff1a; 一、进程的概念及组成 我们通过一个例子来说明进程的概念以及程序和进程的区别。 我们在Windows操作系统中打开任务管理器&#xff0c;在任务管理器当中能看到此时系统当中运行的进程有哪些&#xff0c;如下图所示&#xff1a; 此时&#…

【前端】vue+html+js 实现table表格展示,以及分页按钮添加

一. 问题描述 数据条数太多显示到页面上时可能会渲染较慢&#xff0c;因此需要截取数据进行展示。 二. 代码写法 思路&#xff1a;按照上述图示思路&#xff0c;需要有两个数据列表&#xff0c;一个存储的是所有的列表数据&#xff0c;一个存储的是展示的数据列表&#xff0c…

蒙特卡罗——三门问题python代码实现

三门问题 b站李永乐老师讲解三门问题 python蒙特卡罗模拟 #模拟三门问题 import random as rd #n:模拟次数,m:中奖次数 n100000 m0 for i in range(n):#车位于的门号carrd.randint(0,2)#人随机选择一个门doorrd.randint(0,2)#主持人展示空门empties{0,1,2}-{car,door}emptyrd…

jmeter基准测试详解

配置基准测试策略&#xff1a;单线程连续发送请求5分钟 脚本&#xff1a;基准测试.jmx 提取码: 0000 登录接口换成自己需要的登录接口即可 一、基准测试脚本配置 线程组下添加图表插件&#xff1a;TPS、响应时间、服务器资源 linux服务器在serveragent目录下启动serveragen…

Golang | Leetcode Golang题解之第395题至少有K个重复字符的最长子串

题目&#xff1a; 题解&#xff1a; func longestSubstring(s string, k int) (ans int) {for t : 1; t < 26; t {cnt : [26]int{}total : 0lessK : 0l : 0for r, ch : range s {ch - aif cnt[ch] 0 {totallessK}cnt[ch]if cnt[ch] k {lessK--}for total > t {ch : s[…

智能翻译新时代:深入解析AI驱动的翻译软件优势

现在语言已经不再是我们学习交流的难点了&#xff0c;因为我们的身边涌现了一批类似百度在线翻译这样的翻译工具为我们与不了的语言直接搭建其一个桥梁。这次我们就来一起探讨有什么好用的翻译工具吧。 1.福昕在线翻译 链接直达&#xff1a;https://fanyi.pdf365.cn/doc 对…

[Redis] Redis中的String类型

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

comfyui中的几种inpainting工作流对比

inpainting方法集合_sdxl inpaint教程-CSDN博客文章浏览阅读150次。1.32G,通过它可以将所有的sdxl模型转成sdxl_inpaint模型,源于fooocus_inpaint_head,将9个通道压缩为4个通道的小型卷积网络,标准模型unet有4个通道,重绘模型有9个通道,inpaint_model_head和inpaint mode…

Jupyter Notebook 修改默认路径

Jupyter Notebook 修改默认路径 1、默认路径 安装anaconda后&#xff0c;jupyter notebook默认路径下很多文件&#xff0c;很乱&#xff0c;所以为了创建一个干净的文件夹专门存放我的python项目&#xff0c;修改jupyter notebook的文件路径 这是我现在打开jupyter notebook…

常见概念 -- 光回波损耗

什么是回波损耗 回波损耗&#xff0c;又称为反射损耗&#xff0c;当高速信号进入或退出光纤的某个部分&#xff08;例如光纤连接器&#xff09;&#xff0c;不连续和阻抗不匹配会引起反射&#xff0c;这就是光纤回波损耗。器件的回波损耗Return Loss(RL)是光信号的输入端口的反…

【信创】推荐一款在龙芯CPU终端上使用的WiFi接收器 _ 统信 _ 麒麟

原文链接&#xff1a;【信创】推荐一款在龙芯CPU终端上使用的WiFi接收器 | 统信 | 麒麟 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在龙芯CPU架构的台式机上如何安装和使用无线WiFi接收器的文章。对于使用龙芯CPU的台式机用户来说&#xff0c;安装并配置WiF…

新版智慧职教(zjy2域名开头的)怎么下载课件?一篇文章教会你

文章目录 1、引言2、痛点3、解决方法 &#x1f343;作者介绍&#xff1a;双非本科大四网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发&#xff0c;目前开始人工智能领域相关知识的学习 &#x1f985;个人主页&#xff…

Redis面试必备:Redis两种内存回收策略,Redis键空间、过期字典等

请记住胡广一句话&#xff0c;所有的中间件所有的框架都是建立在基础之上&#xff0c;数据结构&#xff0c;计算机网络&#xff0c;计算机原理大伙一定得看透&#xff01;&#xff01;~ 1. Redis数据库 1.1 Redis数据库的理解 我们可以把Redis的数据库和MySQL的数据库理解成…