logback下日志输出前处理操作——以日志脱敏为例

news/2025/3/18 3:22:28/文章来源:https://www.cnblogs.com/zhaodongge/p/18342022

使用lockback

目前Java Spring服务在打印日志时一般使用slf4j和logback这种组合,其基本原理图如下

img

具体的:大多数会先定义一个loackback-dev.xml文件,而后使用<appender>标签定义输出格式

<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_FILE}</file><!--滚动策略,基于时间策略 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_FILE}.%d{yyyyMMddHH}</fileNamePattern><maxHistory>168</maxHistory></rollingPolicy><!-- 日志的格式化 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>[%level][%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}][%logger:%L][%thread]||traceid=%X{traceId}||spanid=%X{spanId}||hintCode=%X{hintCode}||hintContent=%X{hintContent}||uri=%X{uri}||caller=%X{caller}||ip=%X{ip}||proc_time=%X{proc_time}||%msg%n</pattern><charset>utf8</charset></encoder>
</appender>

如果使用了Lombok提供的@slf4j注解来输入日志,它会自动生成一个名为 log 的日志对象,用于在程序中输出日志信息。

具体使用时会在应用中

log.info("this is a testing log!");

在使用这条语句到打印出日志到指定位置,总共会经过六个步骤( 官方文档地址,中译版地址)

第一步:获取过滤器链

如果存在,则 TurboFilter 过滤器会被调用,Turbo 过滤器会设置一个上下文的阀值,或者根据每一条相关的日志请求信息,例如:Marker, LevelLogger, 消息,Throwable 来过滤某些事件。如果过滤器链的响应是 FilterReply.DENY,那么这条日志请求将会被丢弃。如果是 FilterReply.NEUTRAL,则会继续执行下一步,例如:第二步。如果响应是 FilterRerply.ACCEPT,则会直接跳到第三步。

第二步:应用基本选择规则

在这步,logback 会比较有效级别与日志请求的级别,如果日志请求被禁止,那么 logback 将会丢弃调这条日志请求,并不会再做进一步的处理,否则的话,则进行下一步的处理。

第三步:创建一个 LoggingEvent 对象

如果日志请求通过了之前的过滤器,logback 将会创建一个 ch.qos.logback.classic.LoggingEvent 对象,这个对象包含了日志请求所有相关的参数,请求的 logger,日志请求的级别,日志信息,与日志一同传递的异常信息,当前时间,当前线程,以及当前类的各种信息和 MDC。MDC 将会在后续章节进行讨论。

第四步:调用 appender

在创建了 LoggingEvent 对象之后,logback 会调用所有可用 appender 的 doAppend() 方法。这些 appender 继承自 logger 上下文。

所有的 appender 都继承了 AppenderBase 这个抽象类,并实现了 doAppend() 这个方法,该方法是线程安全的。AppenderBase 的 doAppend() 也会调用附加到 appender 上的自定义过滤器。自定义过滤器能动态的动态的添加到 appender 上,在过滤器章节会详细讨论。

第五步:格式化输出

被调用的 Appender 负责格式化 Logging Event。但是,有些 Appender 将格式化 Logging Event 的任务委托给一个 Layout。Layout 将 LoggingEvent 实例格式化为一个字符串并返回。但需要注意的是,某些 Appender(例如 SocketAppender) 并不会把 Logging Event 转化为一个字符串,而是进行序列化。因此,它们没有并且也不需要 Layout。

第六步:发送 LoggingEvent

当日志事件被完全格式化之后将会通过每个 appender 发送到具体的目的地。

下面是执行上面六个步骤的UML图

image-20240804165844369

我们不难发现,Layout类操作时,会返回一个String类型变量,这个就是我们指定的info方法里的字符串,默认情况下logback直接返回,具体的处理类如下

public class MessageConverter extends ClassicConverter {public String convert(ILoggingEvent event) {return event.getFormattedMessage();}
}

其并没有做什么操作,所以可以从这里入手继承抽象类ClassicConverter,重写convert方法

重写ClassicConverter类

public class DesensitizedMessageConverter extends ClassicConverter {public static final int LOG_MAX_LENGTH = 10000;public String desensitization(String content) {// 这里是真正进行操作的方法,此处是日志脱敏,具体实现可以自己定义content = RegexUtils.desensitization(content);return content;}@Overridepublic String convert(ILoggingEvent iLoggingEvent) {String source = iLoggingEvent.getFormattedMessage();try {// 日志超长处理if (source.length() > LOG_MAX_LENGTH) {source = StringUtils.substring(source, 0, LOG_MAX_LENGTH) + "<<<";}return desensitization(source);} catch (Exception e) {log.error("DesensitizedMessageConverter convert error", e);}return source;}
}

需要注意的是,尽管logback的日志输出是异步的,这里也做了一下日志截断操作,避免由于日志过长,脱敏(或者其他操作)长耗时,造成性能问题,因为这个异步操作是通过一个BlockingQueue<E> blockingQueue;来执行日志时间的输出,默认情况下超过队列80%容量是,会丢弃info级别以下的日志

使用与生效

重写了转换类后,还需要使其生效,将自定义的转换类配置到logback配置文件中,位置在<configuration>标签下

<configuration><!-- 自定义的日志转换类  --><conversionRule conversionWord="dmsg" converterClass="com.xxx.xxx.xxxx.log.DesensitizedMessageConverter"/><appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_FILE}</file><!--滚动策略,基于时间策略 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_FILE}.%d{yyyyMMddHH}</fileNamePattern><maxHistory>168</maxHistory></rollingPolicy><!-- 日志的格式化 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>[%level][%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}][%logger:%L][%thread]||traceid=%X{traceId}||spanid=%X{spanId}||hintCode=%X{hintCode}||hintContent=%X{hintContent}||uri=%X{uri}||caller=%X{caller}||ip=%X{ip}||proc_time=%X{proc_time}||%dmsg%n</pattern><charset>utf8</charset></encoder></appender>
</configuration>

其中conversionWord="dmsg" 是自定义的占位符,输出日志时在<pattern>标签下使用%dmsg来生效,需要注意的一点是conversionRule需要注意放置的位置,避免由于加载顺序而失效。

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

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

相关文章

边分治维护强连通分量(CF1989F,P5163)

这里的边分治和树上的点分治边分治不一样,是维护强连通分量用的,每条边有一个出现时间,通过将每条边按连通关系分流重新排列,从而维护每个时间点整张图的连通性。具体的,这个算法是维护这样的一类问题: n 个点,m 条边按时间顺序依次加入,每加入一条边,你需要回答一些问…

使用 C# 和 ONNX 來玩转Phi-3 SLM

LLM 席卷世界刷新 AI 的认知之后,由于 LLM 需要的硬件要求实在太高,很难在普通设备上运行,因此 SLM 逐漸受到重視,Phi-3 SLM 是由 Microsoft 所开发的模型,可以在你的电脑、手机等设备来运行,小型语言模型 (SLM) 和 ONNX 的结合改变了 AI 互操作性的游戏规则。让我们展…

到底什么是@RestController

@RestController是Spring框架的一个注解,通常用于标识一个类是RESTful服务的Controller。 @RestController经常用来处理HTTP请求,是SpringMVC中用于构建RESTful Web服务的注解,是@Controller注解的变体 通过@RestController注解,SpringMVC可以识别出这个类是一个控制器这个…

【已解决】戴尔 Inspiron 5457 和 5557 启动报错:Invalid configuration information - please run SETUP program.

场景 我使用的是戴尔15-5557的笔记本电脑,在某次开机的时候系统提示:Invalid configuration information - please run SETUP program.虽然的点击Continue可以正常进入系统,但是每次开机都要来上这么一下真的很烦人,于是想着解决一下。 试错过程 1. BIOS调整刚开始以为是自…

6-3使用GPU训练模型

当参数迭代过程成为训练时间的主要瓶颈时,我们通常的方法是应用GPU来进行加速。深度学习的训练过程常常非常耗时,一个模型训练几个小时是家常便饭,训练几天也是常有的事情,有时候甚至要训练几十天。 训练过程的耗时主要来自于两个部分,一部分来自数据准备,另一部分来自参…

从 0 开始安装和运行 Cangjie (仓颉)

在 Windows 上运行你的第一个仓颉应用程序标准方法 参照 配置开发环境 的描述,下载 Cangjie for DevEco Studio 插件 DevEco Studio NEXT Developer Beta2-Cangjie Plugin(5.0.3.500)。然后在 DevEco Studio NEXT Developer Beta2 中从本地磁盘安装插件,选择下载好的 "d…

启动静态文件中间件

在启动项 Program.cs 文件中添加//app.UseStaticFiles(); // 启动静态文件中间件,默认访问wwwroot app.UseStaticFiles(new StaticFileOptions() {//修改默认访问地址为MyStaticFiles文件FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRoo…

变异系数在fNIRS数据分析中有效性讨论

问题变异系数又称CV,它是无量纲的,定义为概率分布离散程度的归一化程度。在概率论中常常用来作为比较两组数据离散程度的指标,其在fNIRS信号这类连续信号中常常用来检测通道的信号质量好坏,阈值包括0.1、0.15和0.25等,阈值越大越宽松,当某个通道的CV值超过设定的阈值时判…

使用python对Excel表格某个区域保存为图片

实际工作中,我们经常会把表格某个区域(如:A1:F5)或某个图形保存为图片,如何用python自动做到这一点?不知屏幕前的小伙伴有没有遇到过类似的需求,此刻脑海里有木有一丢丢思路。python操作excel的第三方库有很多,个个都有各自的绝招和擅长的应用场景,简单罗列一下:pye…

位段 -- 内存布局详解-浅谈C语言

目录位段的介绍位段使用示例:位段的内存分配Example内存分配解析: ## 位段 位段的介绍位段(二进制位):就是按位存储位段(bit-field)是C语言中的一种特殊数据类型,它允许将一个字节分成几个部分,并为每个部分指定特定的位数,以便在内存中存储和访问这些部分。 其中位段相…

chrome查看web socket消息

1. 打开目标页面 2. f12--》网络--》WS,然后刷新页面( 如果不刷页面,就会看不到 websocket 请求,因为 websocket 是长连接,页面加载后只发出一次连接请求,不像 http 接口,不用刷新页面,待会儿也能看到,因为 http 接口是短连接,调用一次发出一次请求 ),如下所示: