序: 这段时间因为维护的项目存在大量日志打印, 严重拖慢整体响应时间, 在做性能优化的工作中对这块内容进行了升级换代, 由以前的 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 的升级工作也就差不多做完啦~恭喜
来源: https://www.cnblogs.com/shuyuq/p/10600222.html