当前位置: 首页 > news >正文

logback日志脱敏后异步写入文件

        大家项目中肯定都会用到日志打印,目的是为了以后线上排查问题方便,但是有些企业对输出的日志包含的敏感(比如:用户身份证号,银行卡号,手机号等)信息要进行脱敏处理。

       哎!我们最近就遇到了日志脱敏的改造。可以说是一波三折。

        浩浩荡荡的日志脱敏改造就这样开始..........

              第一季 :在项目中所有log.info方法输出日志的地方手工脱敏,很low的一种方法

        初期想法很简单,就是根据业务,判断哪些info输出的地方可能包含敏感信息,然后进行手工脱敏。但是有很大弊端,一是工作量大,二是业务不熟悉很难一次改全。

脱敏工具类:

package com.lsl.utills;public class Utils {public static String checkParams(String str){if (str != null){String strnew = str.replaceAll("1[3-9]\\d{9}","***");return strnew;}else {return "";}}
}

代码中调用这个工具类:

package com.lsl.controller;import com.lsl.utills.Utils;
import com.lsl.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/lsl")
public class LogbackTestController {private static final Logger LOG = LoggerFactory.getLogger(LogbackTestController.class);@PostMapping(value = "qryUser", produces = "application/json;charset=UTF-8")@ResponseBodypublic String qryUser(){User user = new User();user.setUserName("LSL");user.setUserPwd("123@asd");user.setUserAddr("北京海淀");user.setUserAge(21);user.setUserTel("15803125588");LOG.info("用户信息:{}",user.toString());LOG.info("脱敏后的用户信息:{}", Utils.checkParams(user.toString()));return "success";}
}

结果截图:

        这种情况确实也能达到脱敏的目的,但是如果代码中有好多info日志输出,那么都需要改动,工作量太大,还容易拉下没有改动的地方。其实我们初期就是这种脱敏,反复改了好几次,总有遗漏的地方忘记改了。

        第二季:想研究一种省时省力的方式,能不能通过AOP切入log.info方法进行统一脱敏

大概思路,就是创建一个切面,在调用info方法前把打印内容通过上面的工具类脱敏后在打印。

切面:

package com.lsl.config;import com.lsl.utills.Utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;@Aspect
public class LogInfoAspect {@Pointcut("execution(* org.slf4j.Logger.info(..))")public void loginfoPointcut(){}@Before("loginfoPointcut() && args(msg)")public void bfLogInfo(ProceedingJoinPoint joinPoint,String msg) throws Throwable{System.out.println("切入前参数msg=" + msg);String newStr = Utils.checkParams(msg);System.out.println("脱敏处理后参数=" + newStr);joinPoint.proceed(new Object[]{newStr});}@Around("loginfoPointcut() && args(msg)")public void adLogInfo(ProceedingJoinPoint joinPoint,String msg) throws Throwable{
//        String arg = (String)joinPoint.getArgs()[0];System.out.println("切入前参数msg=" + msg);String newStr = Utils.checkParams(msg);System.out.println("脱敏处理后参数=" + newStr);joinPoint.proceed(new Object[]{newStr});}
}

结果是:没法切入到info方法,也就无法脱敏了

如下图:

原因也很简单:AOP是交付spring托管的bean才能使用动态代理,实现切入进行操作。然后logback并没有由spring托管,所以不行。

我后来想到,在配置类里交付spring托管不就行了,但是也不行,大家猜猜是什么原因呢?

                        第三季:利用logback脱敏并实现异步写入日志文件

大概思路是,需要自己写脱敏转换器,然后引入logback.xml中,异步写入文件比较方便,网上好多资料,大家可以自行查询。

脱敏转换器:

package com.lsl.config;import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.StringUtils;import java.util.regex.Matcher;
import java.util.regex.Pattern;public class SensitiveConverter extends MessageConverter {//手机号正则private static final String PHONE_REG = "(1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}|[96]\\d{7}|6[68]\\d{5}|09\\d{8})([^@^\\d]|$)";//身份证号正则private static final String IDCARD_REG = "";//脱敏字符private static final String SECRET = "***************";//要脱敏的类型private static String sensitiveType;public static void setSensitiveType(String sensitiveType){SensitiveConverter.sensitiveType = sensitiveType;}@Overridepublic String convert(ILoggingEvent event){String requestLogMsg = event.getFormattedMessage();return filtrSensitive(requestLogMsg,sensitiveType);}public String filtrSensitive(String content,String sensitiveType){try {if (StringUtils.isBlank(content)){return content;}//手机号脱敏if (sensitiveType.contains("phone")){content = filterPhone(content);}//身份证脱敏if (sensitiveType.contains("idcard")){}return content;} catch (Exception e) {return content;}}private static String filterPhone(String num){Pattern pattern =  Pattern.compile(PHONE_REG);Matcher matcher = pattern.matcher(num);StringBuffer sb = new StringBuffer();while (matcher.find()){String matchResult = matcher.group();if (!StringUtils.isNumeric(matchResult.substring(matchResult.length() - 1))){//大陆手机号if (matchResult.startsWith("1")){matcher.appendReplacement(sb,baseSensitive(matchResult,3,5));}//港澳手机号if (matchResult.startsWith("6") || matchResult.startsWith("9")){}}else {//大陆手机号if (matchResult.startsWith("1")){matcher.appendReplacement(sb,baseSensitive(matchResult,3,4));}//港澳手机号if (matchResult.startsWith("6") || matchResult.startsWith("9")){}}}matcher.appendTail(sb);return sb.toString();}private static String baseSensitive(String str,int startlen,int endlen){if (StringUtils.isBlank(str)){return "";}StringBuffer sb = new StringBuffer();sb.append(SECRET);return StringUtils.left(str,startlen).concat(StringUtils.leftPad(StringUtils.right(str,endlen),str.length()- startlen,sb.toString()));}}
package com.lsl.config;import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class SensitiveConverterProperties implements InitializingBean {@Value("${logging.sensitive.type}")private String sensitiveType;@Overridepublic void afterPropertiesSet() throws Exception {SensitiveConverter.setSensitiveType(this.sensitiveType);}public String getSensitiveType() {return sensitiveType;}public void setSensitiveType(String sensitiveType) {this.sensitiveType = sensitiveType;}
}

application.properties文件


server.port=8080logging.sensitive.type=phone

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!--    转换配置 必选配置--><conversionRule conversionWord="sensitiveMsg" converterClass="com.lsl.config.SensitiveConverter"> </conversionRule><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %sensitiveMsg%n</pattern></encoder></appender><!-- 按照每天生成日志文件 --><appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>30</maxHistory></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %sensitiveMsg%n</pattern></encoder></appender><!-- 异步日志配置 --><appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="ROLLING" /></appender><!-- 项目包下所有info日志输出到控制台 --><logger name="com.lsl" level="INFO" additivity="false"><appender-ref ref="CONSOLE" /></logger><!-- 项目包下所有info日志异步输出到文件 --><logger name="com.lsl" level="INFO" additivity="false"><appender-ref ref="ASYNC_FILE" /></logger><!-- Root Logger --><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="ROLLING" /></root>
</configuration>

controoler验证

package com.lsl.controller;import com.lsl.vo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/lsl")
public class LogbackTestController {private static final Logger LOG = LoggerFactory.getLogger(LogbackTestController.class);@PostMapping(value = "qryUser", produces = "application/json;charset=UTF-8")@ResponseBodypublic String qryUser(){User user = new User();user.setUserName("LSL");user.setUserPwd("123@asd");user.setUserAddr("北京海淀");user.setUserAge(21);user.setUserTel("15803125588");LOG.info("用户信息:{}",user.toString());return "success";}
}

验证截图

总结:

利用logback的脱敏转换器是非常方便且灵活的。自己可以定义各种业务敏感信息的脱敏策略,我这里面只写了手机号的脱敏策略。而且在配置文件properties中可以配置对那些敏感信息进行脱敏。

比如:logging.sensitive.type=phone,idcard  

这样就是手机号和身份证号同时进行脱敏,只是具体的身份证号的脱敏规则,我以后在补上吧。

相关文章:

logback日志脱敏后异步写入文件

大家项目中肯定都会用到日志打印&#xff0c;目的是为了以后线上排查问题方便&#xff0c;但是有些企业对输出的日志包含的敏感(比如&#xff1a;用户身份证号&#xff0c;银行卡号&#xff0c;手机号等)信息要进行脱敏处理。 哎&#xff01;我们最近就遇到了日志脱敏的改造。可…...

电容的基本知识

1.电容的相关公式 2.电容并联和串联的好处 电容并联的好处: 增加总电容值: 并联连接的电容器可以增加总的电容值,这对于需要较大电容值来滤除高频噪声或储存更多电荷的应用非常有用。 改善频率响应: 并联不同的电容值可以设计一个滤波器,以在特定的频率范围内提供更好的滤…...

【Axure高保真原型】分级树筛选中继器表格

今天和大家分享分级树筛选中继器表格的原型模板&#xff0c;点击树的箭头可以展开或者收起子级内容&#xff0c;点击内容&#xff0c;可以筛选出该内容及子级内容下所有的表格数据。左侧的树和右侧的表格都是用中继器制作的&#xff0c;所以使用也很方便&#xff0c;只需要在中…...

STM32 I2C通信:硬件I2C与软件模拟I2C的区别

文章目录 STM32 I2C通信&#xff1a;硬件I2C与软件模拟I2C的区别。一、硬件I2C速度快&#xff1a;实现简单&#xff1a;稳定性好&#xff1a; 二、软件模拟I2C灵活性高&#xff1a;支持多路通信&#xff1a; 三、选择哪种方式&#xff1f; STM32 I2C通信&#xff1a;硬件I2C与软…...

服务器新建用户

文章目录 前言一、步骤二、问题三、赋予管理员权限总结 前言 环境&#xff1a; 一、步骤 创建用户需要管理员权限sudo sudo useradd tang为用户设置密码 sudo passwd tang设置密码后&#xff0c;可以尝试使用 su 切换到 tang 用户&#xff0c;确保该用户可以正常使用&#…...

鸿蒙开发融云demo发送图片消息

鸿蒙开发融云demo发送图片消息 融云鸿蒙版是不带UI的&#xff0c;得自己一步步搭建。 这次讲如何发送图片消息&#xff0c;选择图片&#xff0c;显示图片消息。 还是有点难度的&#xff0c;好好看&#xff0c;好好学。 一、思路&#xff1a; 选择图片用&#xff1a;photoVie…...

音视频入门基础:AAC专题(11)——AudioSpecificConfig简介

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…...

OpenCV基本操作(python开发)——(8)实现芯片瑕疵检测

OpenCV基本操作&#xff08;python开发&#xff09;——&#xff08;1&#xff09; 读取图像、保存图像 OpenCV基本操作&#xff08;python开发&#xff09;——&#xff08;2&#xff09;图像色彩操作 OpenCV基本操作&#xff08;python开发&#xff09;——&#xff08;3&…...

聚水潭商品信息集成到MySQL的高效解决方案

聚水潭商品信息集成到MySQL的技术案例分享 在数据驱动的业务环境中&#xff0c;如何高效地实现不同系统之间的数据对接和集成&#xff0c;是每个企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例&#xff1a;将聚水潭平台上的商品信息单集成到BI斯莱蒙的MySQL数据…...

# centos6.5 使用 yum list 报错Error Cannot find a valid baseurl for repo bas 解决方法

centos6.5 使用 yum list 报错Error Cannot find a valid baseurl for repo bas 解决方法 一、问题描述&#xff1a; centos6.5 使用 yum list 报错Error Cannot find a valid baseurl for repo bas 如下图&#xff1a; 二、问题分析&#xff1a; 官方已停止对CentOS 6的更…...

【专题】2023-2024中国保险数字化营销调研报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p38063 在时代浪潮的推动下&#xff0c;中国保险行业正经历着一场波澜壮阔的变革之旅。 2023 年&#xff0c;中国经济迈向高质量发展阶段&#xff0c;保险公司纷纷聚焦队伍转型&#xff0c;专业化、职业化代理人成为行业新方向。回…...

““ 引用类型应用举例

#include <iostream> //使能cin(),cout(); #include <stdlib.h> //使能exit(); #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和resetiosflags(); //setbase( char x )是设置输出数字的基数,如输出进制数则用se…...

数字图像处理 - 基于ubuntu20.04运行.NET6+OpenCVSharp项目

一、简述 上一篇Ubuntu20.04 更新Nvidia驱动 + 安装CUDA12.1 + cudnn8.9.7-CSDN博客,记录了Ubuntu20.04 更新Nvidia驱动 + 安装CUDA12.1 + cudnn8.9.7的过程,最终的目的是要这些服务器上运行.net6的程序,进行图像处理、onnxruntime推理等。 这里记录进行OpenCVSharp的安装和…...

git cherry-pick用法详解

git cherry-pick 是 Git 中一个非常有用的命令&#xff0c;它允许你选择一个特定的提交&#xff08;commit&#xff09;并将其变更应用到当前分支上。这个功能在你需要将某个分支上的某个或某些特定提交合并到另一个分支时特别有用&#xff0c;而不需要将整个分支合并过去。 基…...

HCIP-HarmonyOS Application Developer V1.0 笔记(一)

HarmonyOS的系统特性 硬件互助&#xff0c;资源共享;一次开发&#xff0c;多端部署;统一OS&#xff0c;弹性部署。 分布式软总线&#xff1a;分布式任务调度、分布式数据管理、分布式硬件虚拟化的基座 18N的独立设备 1个手机&#xff0c;8种设备&#xff08;车机&#xff0c…...

开发流程初学者指南——需求分析

目录 从零开始理解需求分析什么是需求分析&#xff1f;需求分析的目标需求分析的基本原则需求分析的各个阶段需求分析的常用方法和工具编写需求文档总结 从零开始理解需求分析 需求分析是软件开发过程中不可或缺的一环&#xff0c;它帮助我们明确用户的需求&#xff0c;确保最…...

CRM平台排名:用户体验与客户满意度的深度解析

在数字化时代&#xff0c;客户关系管理&#xff08;CRM&#xff09;系统已成为企业不可或缺的工具&#xff0c;它帮助企业优化客户互动&#xff0c;提升销售效率&#xff0c;并增强客户满意度。本文将深度解析各大CRM平台的用户体验和客户满意度&#xff0c;盘点它们的品牌介绍…...

WIFI、NBIOT、4G模块调试AT指令连接华为云物联网服务器(MQTT协议)

一、前言 随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;越来越多的设备开始连接到互联网&#xff0c;形成了一个万物互联的世界。在这个背景下&#xff0c;设备与云端之间的通讯变得尤为重要。 本文将探讨几种常见的无线通信模块——EC20-4G、Air724ug-4…...

打造自己的RAG解析大模型:(新技能)企业垂类数据标注(一)

在上一篇文章中&#xff0c;我们以通用版面分析服务为例&#xff0c;展示了从模型发布到API集成的完整流程。如果你成功完成了这些步骤&#xff0c;值得庆祝&#xff01;这不仅意味着你已成功安装PaddleX&#xff0c;还掌握了利用它发布OCR和目标检测等大模型服务的能力&#x…...

怎么理解ES6 Proxy

Proxy 可以理解成&#xff0c;在目标对象之前架设一层 “拦截”&#xff0c;外界对该对象的访问&#xff0c;都必须先通过这层拦截&#xff0c;因此提供了一种机制&#xff0c;可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理&#xff0c;用在这里表示由它来 “代理…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...