Log4j2自定义插件实现自定义日志打印功能(脱敏/加密)

2023-11-18

Log4j2 中文文档

1. 自定义appender插件

import cn.hutool.core.util.DesensitizedUtil;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * log4j1.x重写log4j的PatternLayout,实现日志信息中敏感信息的编码或加密
 * log4j2.x重写log4j的AbstractStringLayout,实现日志信息中敏感信息的编码或加密
 *
 * @author Zyx
 * @since 2022/8/24 10:55
 */
@Plugin(name = "Log4jEncodeLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
public class Log4jEncodeLayout extends AbstractStringLayout {

    /**
     * 手机号正则匹配式
     * 实测雪花算法生成的Id可能会被手机号正则匹配到,故加了关键正则过滤:
     *  (?<![0-9a-zA-Z]):手机号前面紧挨的不能是字母和数字
     *  (?![0-9a-zA-Z]):手机号后面紧挨的不能是字母和数字
     */
    private final static Pattern PHONE_PATTERN = Pattern.compile("(?<![0-9a-zA-Z])1[345789]\d{9}(?![0-9a-zA-Z])");


    private PatternLayout patternLayout;

    protected Log4jEncodeLayout(Charset charset, String pattern) {
    	//调用父类设置基本参数
        super(charset);
        //PatternLayout 是原本的输出对象,用来获取到原本要输出的日志字符串
        patternLayout = PatternLayout.newBuilder().withPattern(pattern).build();
    }

    @Override
    public String toSerializable(LogEvent event) {
        //调用原本的 toSerializable 方法,获取到原本要输出的日志
        String message = patternLayout.toSerializable(event);

        //在原本输出的字符串上做正则匹配过滤
        Matcher match = PHONE_PATTERN.matcher(message);

        StringBuffer sb = new StringBuffer();

        while (match.find()) {
            match.appendReplacement(sb, DesensitizedUtil.mobilePhone(match.group()));
        }
        match.appendTail(sb);// 增加

		// 将脱敏后的日志输出
        return sb.toString();
    }

	//定义插件传入的参数
    @PluginFactory
    public static Layout createLayout(
            @PluginAttribute(value = "pattern") final String pattern,
            // LOG4J2-783 use platform default by default, so do not specify
            // defaultString for charset
            @PluginAttribute(value = "charset") final Charset charset) {
        return new Log4jEncodeLayout(charset, pattern);
    }
}

2. log4j2.xml配置

需要修改两个地方:

  1. Configuration 标签中 packages 参数需指定自定义插件的位置
  2. 日志打印的地方替换为上面自定义的插件: <Log4jEncodeLayout pattern="..." charset="UTF-8"/>
<?xml version="1.0" encoding="UTF-8"?>
<!--packages 参数指定插件包路径,多个路径用逗号隔开-->
<Configuration status="INFO" name="XMLConfigTest" packages="org.apache.logging.log4j.test,com.zyx.demo">
    <Properties>
        <Property name="PATTERN">
            %d{yyyy-MM-dd HH:mm:ss SSS} [%p] [c=%c{1}] [%thread] %m%n
        </Property>
        <property name="MODULE_NAME">log4j2-demo</property>
        <property name="LOG_HOME">/data</property>
    </Properties>



    <Appenders>
        <Console name="STDOUT">
            <!--<PatternLayout>-->
            <!--    <pattern>${PATTERN}</pattern>-->
            <!--</PatternLayout>-->
            <!--将原先的日志输出替换为自定义的日志输出appender插件-->
            <Log4jEncodeLayout pattern="${PATTERN}" charset="UTF-8"/>
        </Console>
        <RollingFile name="ROLLINGFILE" fileName="${LOG_HOME}/${MODULE_NAME}.log"
                     filePattern="${LOG_HOME}/log/${MODULE_NAME}-%d{yyyy-MM-dd}-%i.log.gz">
            <!--<PatternLayout-->
                    <!--pattern="[${MODULE_NAME}] %d{yyyy-MM-dd HH:mm:ss SSS} [%p] [c=%c{1}] [%thread] %m%n"/>-->
            <!--将原先的日志输出替换为自定义的日志输出appender插件-->
            <Log4jEncodeLayout pattern="[${MODULE_NAME}] %d{yyyy-MM-dd HH:mm:ss SSS} [%p] [c=%c{1}] [%thread] %m%n" charset="UTF-8"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true"
                                           interval="1" />
                <SizeBasedTriggeringPolicy size="100MB"/>
                <CronTriggeringPolicy schedule="0 0 * * * ?"/> <!-- 这里是每小时监测一次 -->
            </Policies>
            <DefaultRolloverStrategy max="100">
                <Delete basePath="${LOG_HOME}" maxDepth="3">
                    <IfFileName glob="*/${MODULE_NAME}-*.log.gz"/>
                    <IfLastModified age="30d"/> <!-- 这里保留30天 -->
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>

    <Loggers>
        <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
        <Root level="INFO">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="ROLLINGFILE"/>
        </Root>
        <Logger name="com.snbc.vems" level="INFO" additivity="false">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="ROLLINGFILE"/>
        </Logger>
        <Logger name="org.apache" level="WARN" additivity="false" includeLocation="false">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="ROLLINGFILE"/>
        </Logger>
        <Logger name="org.mybatis" level="WARN" additivity="false" includeLocation="false">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="ROLLINGFILE"/>
        </Logger>
        <Logger name="org.hibernate" level="WARN" additivity="false" includeLocation="false">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="ROLLINGFILE"/>
        </Logger>
        <Logger name="org.springframework" level="WARN" additivity="false" includeLocation="false">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="ROLLINGFILE"/>
        </Logger>
    </Loggers>
</Configuration>

3. 参数说明

1)定义标签(@Plugin)

@Plugin(name = "MyAppender", category = "Core", elementType = "layout", printObject = true)
  • name:插件的名称。请注意,此名称不区分大小写
  • category:用于放置插件的类别。类别名称区分大小写
  • elementType:此插件所属元素的相应类别的名称,当前扩展所属元素的类别是 layout(layout:日志处理重新输出,appender:日志追加处理,如存入数据库中)。
  • printObject:指示插件类是否实现 Object.toString() 方法,消息中使用。

2)定义标签参数或子元素(@PluginFactory)

createAppender 方法,用于 log4j2 在扫描到插件之后根据配置文件中的配置生成插件自定义的插件对象。

  • @PluginAttribute:是指插件的属性,如

    @PluginAttribute("name") String name
    

    对应的 xml 配置是:

    <MyAppender name="MyAppenderTest"></Realtimeval>
    

    会取标签内name的值

  • @PluginElement:是指插件的子元素,如

    @PluginElement("AppenderRef") AppenderRef[] appenderRefs
    

    对应的 xml 配置是:

    <MyAppender name="MyAppenderTest">
    	<AppenderRef ref="AsyncMqLog"/>
    	<AppenderRef ref="AsyncCONSOLE"/>
    </MyAppender>
    

    会获取标签下AppenderRef 元素的值,如果是多个AppenderRef 子元素,将会获取都一个数组,可以根据业务需要自定义元素或者属性。

4. 获取容器中对象

再说一个上下文的问题,log4j2在dao层service层初始化结束之前就已经初始化了,如果采用@Resource这种依赖注入的方式构建bean是行不通的,获取到的只能是null,但是ApplicationContext已经加载,可以通过ApplicationContext手动获取bean。

当我们在 Spring 框架中使用 log4j2 框架时,可能你想要让 Appender 接收外部 spring 容器中的 bean。如果使用 @Autowared 注入获取对象为 null 时,则实现 ApplicationContextAware 接口,通过 ApplicationContext 来直接获取容器中的对象。

5. Mybatis 设置日志打印实现为Log4j2Impl

自定义 Log 对象的实现类,该类中使用 Log4j2 打印日志,同时配置 Mybatis 使用自定义的 Log 对象,即可实现对 Mybatis 打印的 sql 日志脱敏

public class Log4j2Impl implements Log {

    private final Log logImpl;

    /**
     * Instantiates a new Snbc log 4 j 2.
     *
     * @param clazz the clazz
     */
    public Log4j2Impl(String clazz) {
        Logger tmplLog = LogManager.getLogger(clazz);

        if (tmplLog instanceof AbstractLogger) {
            logImpl = new Log4j2AbstractLoggerImpl((AbstractLogger) tmplLog);
        } else {
            logImpl = new Log4j2LoggerImpl(tmplLog);
        }
    }

    public boolean isDebugEnabled() {
        return true;
    }

    public boolean isTraceEnabled() {
        return true;
    }

    public void error(String s, Throwable e) {
        logImpl.error(s, e);
    }

    public void error(String s) {
        logImpl.error(s);
    }

    public void debug(String s) {
        logImpl.debug(s);
    }

    public void trace(String s) {
        logImpl.trace(s);
    }

    public void warn(String s) {
        logImpl.warn(s);
    }
}
mybatis:
    configuration:
		log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl

参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Log4j2自定义插件实现自定义日志打印功能(脱敏/加密) 的相关文章

随机推荐

  • python icon生成小工具

    在项目制作的过程中 有可能会出现一张图片需要有不同的大小去适应不同的设备和位置时 手动去一个个制作比较麻烦 本人通过网上学习粗略敲了一段python脚本 可能有考虑不周之处还请指出 文底有下载链接 old file new file new
  • 将代码上传到gitee

    1 新建gitee仓库 直接点击创建即可 2 到idea点击vcs gt Enable 3 项目点击右键 选中下列 4 选中项目右键 复制进去链接 5 项目右键 选中下列的文件 6 提交 push push 7 去gitee刷新文件已经上传
  • 框架的注解

    文章目录 一 mybatis 1 MyBatis的常用注解 2 MyBatis的注解实现复杂映射开发 二 Spring 1 Spring原始注解 2 Spring新注解 3 注解配置 AOP 详解 三 springMVC 1 Request
  • 爬山算法启发

    爬山算法 是一种局部择优的方法 采用启发式方法 是对深度优先探索的一种改进 它利用反馈信息帮助生成解的决策 属于人工智能算法的一种 相关术词解释 1 启发式方法 简化虚拟机和简化行为判断引擎的结合 简单讲就是提前对某项行为进行检测和判断 拥
  • win10系统安装Nginx

    Nginx是一款自由的 开源的 高性能的HTTP服务器和反向代理服务器 同时也提供了IMAP POP3 SMTP服务 Nginx可以进行反向代理 负载均衡 HTTP服务器 动静分离 正向代理等操作 因为最近在公司使用到了Nginx 第一步
  • nginx目录结构和配置文件详解

    nginx目录结构和配置文件详解 0x00 Nginx 目录结构 Nginx 文件结构比较简洁 主要包括配置文件和二进制可执行程序 通过安装包形式安装的 nginx 文件结构跟各 Linux 发行版目录规则存放配置文件和二进制文件的位置 目
  • 3 Minute Thesis (3MT)

    1 定义 资料来源 https zhuanlan zhihu com p 63325983 utm id 0 3MT原则 要把博士课题介绍给一个受过高等教育但没有专业背景的人并阐述它的重要性 定义 三分钟论文 3MT 是一个学术比赛 帮助当
  • k8s问题 CrashLoopBackOff

    我们创建资源发现资源出现CrashLoopBackOff解决 CrashLoopBackOff 告诉我们 Kubernetes 正在尽力启动这个 Pod 但是一个或多个容器已经挂了 或者正被删除 root localhost kubectl
  • R语言09-单变量绘图(频数分布直方图/折线图)

    使用ggplot绘图系统 运用qplot ggplot两种方式进行单变量绘图示例 直方图 qplot 系统默认柱状图 library ggplot2 qplot x dob day data users 传入参数x和数据集 ggplot 与
  • MIPI CSI-2学习

    CSI Camera Serial Interface 定义了摄像头外设与主机控制器之间的接口 旨在确定摄像头与主机控制器在移动应用中的标准 关键词描述 缩写 解释 CCI Camera Control Interface 物理层组件 通常
  • 1-Axure

    Axure学习 一 原型图 1 原型图作用 描述互联网产品设计的文档 项目中 与相关部门沟通需求的工具 研发 设计 敏捷开发中 简化版的需求文档 PRD MRD 2 原型图种类 线框图 制作快速 低成本描述方案 给设计更多空间 高保真原型图
  • 2.4.2QT之comboBox下拉框

    2 4 2QT之comboBox下拉框 文章目录 2 4 2QT之comboBox下拉框 前言 2 4 2 1 QComboBo 常用的成员函数 2 4 2 2QComboBox 常用的槽函数 2 4 2 3QComboBox 常用的信号
  • 批量上传文件到服务器中,如何批量上传文件到云服务器

    如何批量上传文件到云服务器 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 将文件上传至Linux服务器一般会采用WinS
  • JAVA: quakus程序运行

    mvnw compile quarkus dev
  • Select type&partitions (2)—mysql执行计划(四十八)

    前面说了explain的table是表名 显示在前面的代表驱动表 正常select会出现不同的id 但如果子查询本来是两个select 但被优化成连接查询 就会导致是相同的id union查询会出现临时表 id为null 这个临时表作用于去
  • 连杆坐标系的规定

    z0是沿着关节轴1的方向 一般l0的坐标轴与l1的坐标轴相同 故 两个关节轴间的距离为0 角度为0 即初始 a 和 为0 建立连杆坐标系的步骤 1 找出各关节轴 并标出 或画出 这些轴线的延长线 在下面的步骤2至步骤5中 仅考虑两个相邻的轴
  • 【uni-app报错】选择地址:fail the api need to be declared in the requiredPrivateInfos field in app/ext.json

    uni app报错 errMsg chooseAddress fail the api need to be declared in the requiredPrivateInfos field in app json ext json 笔
  • 多个C语言代码文件编译示例

    多个C语言代码文件编译示例 多个C语言文件的编译在实际项目中会遇到 是模块化编程的重要体现 是必须要学习的 我们先学习一个简单的例子 我们要实现一个加法和减法操作 将加法和减法看成两个独立的功能 头文件和源文件是分离的 方便给其他开发人员使
  • jquery-ui sortable详解

    该插件的用途 使用鼠标重新排列列表或网格中的元素 helper 这个小伙子 总结的不错 Note In order to sort table rows the tbody must be made sortable not the tab
  • Log4j2自定义插件实现自定义日志打印功能(脱敏/加密)

    文章目录 1 自定义appender插件 2 log4j2 xml配置 3 参数说明 1 定义标签 Plugin 2 定义标签参数或子元素 PluginFactory 4 获取容器中对象 5 Mybatis 设置日志打印实现为Log4j2I