• log4j到log4j2升级迁移方案


    序:这段时间因为维护的项目存在大量日志打印,严重拖慢整体响应时间,在做性能优化的工作中对这块内容进行了升级换代,由以前的log4j升级为log4j2,以实现日志异步打印。接下来记录一下这个费时半个月的迁移踩过的坑!

    相关操作步骤:

    1. 在项目中移除log4j的依赖,并添加log4j2的相关依赖.(选择log4j2的版本时请留意,2.10.x之后的版本是基于java9的!如果有使用到某些特性,请考虑当前项目的jdk版本!)

    <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.9.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.9.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
    <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.9.1</version>
    </dependency>

    我最开始使用的2.11.2版本,因为jdk原因退回到2.9.1(请注意如果你的项目是通过jenkins构建,请将api,core包的依赖直接添加进来!)  

    2.修改项目中所有的报错!(这些都是jar包替换造成的!注意log4j2在实现方面与log4j是有区别的,常用的3个为:自定义appender自定义日志等级获取logger的方式)

    自定义appender方式:

    @Plugin(
            name = "CustomerAppender",
            category = "Core",
            elementType = "appender",
            printObject = true
    )
    
    public final class CustomerAppender extends AbstractOutputStreamAppender<CustomerRollingFileManager> {
    
    
    //TODO
    //此部分为自定义内容    
    
    
    }
    

      

    3.本文以maven依赖管理为例,查看dependencies树,确保项目中没有其他依赖的依赖引入log4j相关jar包

    这个步骤自行解决~~举例如下:

       <dependency>
                <groupId>net.sourceforge.jexcelapi</groupId>
                <artifactId>jxl</artifactId>
                <version>2.6.12</version>
                <exclusions>
                    <exclusion>
                        <artifactId>log4j</artifactId>
                        <groupId>log4j</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
    

      

    4.为步骤三中找到并移除的实现引入需要的桥接包!(此处注意大多数的项目中使用的 都是slf4j的框架,不同的版本使用Log4j2的实现需要的桥接包版本是不一样的!请仔细查看相关版本)

    <!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>x.x.x</version>
            </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
                <version>x.x.x</version>
            </dependency>
    

      请根据实际需要修改对应版本,建议在maven repository中查询版本对应关系

    5.根据原有log4j.xml的配置文件改造log4j2.xml(原来通过java定义的日志等级可以迁移到此处)

    <CustomLevels>
        <CustomLevel name="BUSI" intLevel="350" />
    </CustomLevels>
    

      这里可以根据需要定义name,一级level,注意这个值与log4j定义的不太一样,具体请参考源码中的定义规则,我此处给的350在info等级以上

    6.解决kafka日志推送问题.(log4j推送kafka一般是通过kafka-log4j-appender这个中间包去实现的,在lo4j2下需要更换推送方式,有内置的kafkaAppender,需要在依赖管理中根据需要推送的kafka服务端版本号添加对应的客户端版本号:kafka-clients)

    <!--kafka日志推送-->
            <Kafka name="kafkaAppender" topic="test" ignoreExceptions="true">
                <PatternLayout pattern="${Console_Pattern}" />
                <Property name="bootstrap.servers">x.x.x.x:端口号,x.x.x.x:端口号</Property>
                <Property name="max.block.ms">2000</Property>
            </Kafka>
    

      此处还可以设置ignoreException=false;这个时候需要去对异常做处理,可以获取异常信息.

    需要添加的kafka-clients依赖如下(请修改具体版本):

    <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
            <dependency>
                <groupId>org.apache.kafka</groupId>
                <artifactId>kafka-clients</artifactId>
                <version>0.10.0.0</version>
            </dependency>

    7.解决容器问题!这个并非所有的容器都需要(至少tomcat不需要。。)目前我们服务器端使用的为jboss。在对日志升级后有可能出现对应业务日志打印到jboss的server日志中!这肯定是不允许的!解决办法:在项目的WEB-INF或者META-INF目录下添加:jboss-deployment-structure.xml文件,注意此处放置的位置和文件名都必须是这个!这是jboos规定的。此文件的作用是可以管理jboss的相关依赖,可以在此处排除它的log4j2的实包

    <?xml version="1.0" encoding="UTF-8" ?>
    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
        <deployment>
    
            <exclude-subsystems>
                <!-- 排除 javax.persistence.api 依赖 -->
                <subsystem name="jpa" />
    
                <!-- 排除 org.jboss.logging 依赖 -->
                <subsystem name="logging" />
            </exclude-subsystems>
    
            <exclusions>
                <!-- 排除 org.apache.httpcomponents 依赖 -->
                <module name="org.jboss.resteasy.resteasy-jaxrs" />
    
                <!-- 排除 javax.persistence.api 依赖 -->
                <module name="javaee.api" />
                <module name="javax.persistence.api" />
                <module name="org.hibernate" />
            </exclusions>
    
            <dependencies>
    
                <!-- 排除 org.apache.httpcomponents 依赖 -->
                <!-- <module name="org.apache.httpcomponents" export="true"/> -->
    
                <!-- 排除 org.jboss.logging 依赖 -->
                <!-- <module name="org.jboss.logging" export="true" /> --
    
                <!-- 排除掉jboss的 slf4j 和 log4j 实现,使用我们程序自己的包 -->
                 <!--<module name="org.apache.log4j" export="true" />-->
                 <!--<module name="org.slf4j" export="true" />-->
                <module name="org.apache.commons.logging" export="true" />
                <module name="org.jboss.logging.jul-to-slf4j-stub" export="true" />
    
            </dependencies>
        </deployment>
    </jboss-deployment-structure>

      请根据项目实际需要做相关排除

    8.解决因为包装自定义的logger导致的日志记录中不能正常记录logger打印位置的问题。(这个问题对于直接使用原生logger的项目不会有)在log4j2的api包下我们会发现没有提供可以传递FQCN的接口!所以此处我们需要直接引入core下的具体实现。在实现类中有log.logIfEnabled()方法,此方法允许传入(FQCN,level,maker,message).

    import org.apache.logging.log4j.Level;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.core.Logger;
    
    public abstract class AbstractABFrameLogger {
    
        /** 线程栈查找方法深度 */
        private final static int STACK_DEEP_SIZE = 2;
    
    
        /** log4j把传递进来的callerFQCN在堆栈中一一比较,相等后,再往上一层即认为是用户的调用类 */
        final static String FQCN = AbstractABFrameLogger.class.getName();
    
        protected Logger log;
    
    
        /**
         *
         * @param name name
         */
        public AbstractABFrameLogger(String name) {
            this.log = (Logger) LogManager.getLogger(name);
        }
    
    
    
        /**
         * 基本debug基本,封装打印信息
         * @param objLogInfo Object
         */
        public void debug(Object objLogInfo) {
            log.logIfEnabled(FQCN,Level.DEBUG,null,objLogInfo);
        }
    
    }
    

      

    完成上述步骤后,整个log4j的升级工作也就差不多做完啦~恭喜

  • 相关阅读:
    (转)写好程序注释的十三条建议
    注册表添加NoDrives隐藏盘符(禁用U盘)参数说明
    AJAX实用教程——开篇
    浅谈函数求解与人生
    C#(服务器)与Java(客户端)通过Socket传递对象
    BI开发之——Mdx基础语法(2)
    UML——序列图
    UML——序列图案例总结
    ORM内核原理解析之:延迟加载
    应用程序系统基本设计原则——SOLID
  • 原文地址:https://www.cnblogs.com/shuyuq/p/10600222.html
Copyright © 2020-2023  润新知