关于Log4j 1.x 升级Log4j 2.x 那些事

  • 0x01 为什么要将Log4j 1.x升级到Log4j 2.x?
  • 0x02 如何把Log4j 1.x 升级到log4j2.x ?
    • 2.1 依赖升级篇
      • 2.1.1 基础的依赖
        • 2.1.1.1 普通项目
        • 2.1.1.2 Spring Boot 项目
      • 2.1.2 统一版本依赖
      • 2.1.3 Log4j 1.x API Bridge
      • 2.1.4 Apache Commons Logging Bridge
      • 2.1.5 SLF4J Bridge
      • 2.1.6 JUL Adapter
      • 2.1.7 Log4j API to SLF4J API Adapter
    • 2.2 普通web项目依赖配置汇总
    • 2.3 Spring Boot 项目
    • 2.4 关于web.xml配置
    • 2.5 关于 MDC
    • 2.6 Log4j 2.x 与Jboss 兼容性
      • 2.6.1 问题分析
      • 2.6.2 解决方案
    • 2.7 Jboss 6.x 不兼容Log4j 2.x 冲突问题
      • 2.7.1 问题描述
      • 2.7.2 解决方案
  • 0x03 log4j 2.x XML配置和自定义线程日志
  • 0x04 参考博文

这篇博文来聊聊Log4j 1.x 升级到Log4j 2.x 后发生了改变。

0x01 为什么要将Log4j 1.x升级到Log4j 2.x?

我们知道由于 Log4j 1 代码库存在一些架构缺陷,因此 2015年8月 官方停止维护log4j 1.x

当我们重新打开 Log4j 1.x 官网可以看到如下内容:

上面的英文大致意思说Log4j 1.x 已经停止维护,建议大家都去升级使用Log4j 2.x吧~

既然官方都这么宣布了,那么我们一起来Log4j 2.x 官网看看吧。

打开Log4j 2.x 官网,我们可以看到

如果看不懂的,这里大致翻译下:

Apache Log4j 2是对Log4j的升级,它比其前身Log4j 1.x提供了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些固有问题。

关于 为什么要升级,我这里做下总结:

  • Log4j 1.x 和Logback 配置文件改动重新加载会导致丢失一些日志记录。
  • log4j2 基于LMAX Disruptor library 比Log4j1.x 和logback 快很多
  • Log4j 1代码库存在一些架构缺陷,因此2015年8月log4j 1.x 官方停止维护

总之,我们知道如下几点就够了

  • log4j 2.x 比Log4j 1.x 和Logback 更好更优秀
  • log4j 2.x 接口和实现分离,log4j-api 模块是log4j2日志接口,log4j-core模块是log4j2日志实现。
  • log4j-api 日志接口比Slf4j API接口功能更强大

log4j 2设计架构图

0x02 如何把Log4j 1.x 升级到log4j2.x ?

好了说完了为什么升级,接下来我们聊聊如何升级的问题。

  • 首先我们可以看下官方的升级文档: Log4j 1.x 升级到Log4j 2.x 官方参考资料

你可能看的一头雾水,没关系,我们来看点比较实用的

2.1 依赖升级篇

官方Log4j 1.x 升级Log4j2.x升级参考文档

关于这个依赖升级,下面这个图很重要。

  • Log4j Runtime Dependencies

2.1.1 基础的依赖

2.1.1.1 普通项目

添加最基础的Log4j 2日志依赖如下:

   <!--https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.12.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.12.1</version></dependency>
  • 这里log4j-api是log4j2日志接口,log4j-core 是log4j2日志实现。
  • 查看最新版本

2.1.1.2 Spring Boot 项目

我们只需要如下添加如下依赖即可:

<!--排除默认的logback日志-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

注意事项

  • log4j-slf4j-impl 不能和log4j-to-slf4j同时使用

    • log4j-slf4j-impl 是SLF4J API 作为日志门面,
    • 然后通过该依赖适配成Log4j 2.x API(日志接口),最后交给Log4j 2.x core(impl 日志实现)
  • log4j-to-slf4j 则是将log4j 2.x API 转换成SLF4J API,最后交给SLF4J 实现类。

2.1.2 统一版本依赖

在项目中显示声明的依赖好处理,对于一些传递的依赖如果Log4j 的 版本不一致可能会警告或者错误提示。

解决方法就是添加如下内容:

<dependencyManagement><dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-bom</artifactId><version>2.12.1</version><scope>import</scope><type>pom</type></dependency></dependencies>
</dependencyManagement>

2.1.3 Log4j 1.x API Bridge

如果是老项目,可能有很多代码是使用Log4j 1.x 的API进行的调用,全部更换成新代码无疑是一个头疼的事情。

<dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-1.2-api</artifactId><version>2.12.1</version></dependency>
</dependencies>
  • 需要移除掉所有的之前的Log4j 1.x 相关依赖
  • 正如下图所示,添加以上依赖后就可以将log4j 1.x API与log4j 2.x API 之间做一个适配,最后交给log4j 2.x Core实现。
  • Log4j Runtime Dependencies

2.1.4 Apache Commons Logging Bridge

如果项目之前是实用Commons Logging 作为门面日志,那么官方提供了一个连接桥

<dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-jcl</artifactId><version>2.12.1</version></dependency>
</dependencies>
  • 不需要移除Common Logging 依赖
  • 正如下图所示,添加如上依赖后可以将 Common Logging API 适配成Log4j 2.x API ,然后交给log4j 2.x 实现类实现。
  • Log4j Runtime Dependencies

2.1.5 SLF4J Bridge

如果我们不想要实用log4j-api 作为日志门面(日志接口),而是想用SLF4j 那么可以引入这个依赖。

<dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.12.1</version></dependency>
</dependencies>

注意事项:

  • 不需要移除SLF4J-API 依赖
  • 本质上是 SLF4J 日志门面转Log4j 日志门面
  • 切记,如果使用了这个依赖就不能使用 2.1.6 Log4j to SLF4J Adapter

2.1.6 JUL Adapter

如果之前项目使用的是Java Util Logging门面日志,那么可以加入这个依赖

<dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-jul</artifactId><version>2.12.1</version></dependency>
</dependencies>
  • The Apache Log4j implementation of java.util.logging
  • 正如下图所示,添加如上依赖后可以将 java util logging API 适配成Log4j 2.x API ,然后交给log4j 2.x 实现类实现。
  • Log4j Runtime Dependencies

2.1.7 Log4j API to SLF4J API Adapter

如果代码中实用的是Log4j-2.x-API 日志门面,想实用SLF4作为日志门面,那么需要添加如下依赖

  <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId><version>2.12.1</version></dependency>
  • 本质上是Log4j 2.x API日志门面转SLF4j API 日志门面
  • log4j-slf4j-impl 不能和log4j-to-slf4j同时使用,推荐使用log4j-slf4j-impl,否则会丢失一些log4j 2.x API的一些新特性。

2.2 普通web项目依赖配置汇总

     <!--日志系统 --><!--使用Log4j2 start--><!-- log4j 2.x API 日志门面 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.9.1</version></dependency><!-- log4j 2.x Core 日志实现 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.9.1</version></dependency><!-- Web模块支持--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-web</artifactId><version>2.9.1</version></dependency><!--升级兼容包--><!--该依赖会先Log4j 1.x api 转换成log4j 2.x api ,最后使用log4j2.x 实现类 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-1.2-api</artifactId><version>2.9.1</version></dependency><!--该依赖会将Common Logging API 转换成 Log4jx2.x api,最后使用log4j2.x 实现类 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-jcl</artifactId><version>2.9.1</version></dependency><!--将SLF4j 的实现类替换为Log4J 2实现类--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.9.1</version></dependency><!-- 将java.util.logging API 通过该依赖转换成log4j2.x api,最后使用log4j2.x 实现类 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-jul</artifactId><version>2.9.1</version></dependency><!-- SLF4J API --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.6.6</version></dependency><!--使用Log4j2 end-->

2.3 Spring Boot 项目

对于Spring Boot 新项目, 我们只需要如下添加如下依赖即可:

<!--排除默认的logback日志-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

2.4 关于web.xml配置

如果是传统的web 项目,需要添加在pom.xml中添加如下依赖

 <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-web</artifactId><version>2.12.1</version></dependency>

因为org.apache.logging.log4j.web.Log4jServletContextListener需要

web.xml修改如下:

  <!-- 日志配置文件路径--><context-param><param-name>log4jConfiguration</param-name><param-value>classpath:/log4j2.xml</param-value></context-param><!--日志配置监听器 --><!-- log4j2 start --><listener><listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class></listener><filter><filter-name>log4jServletFilter</filter-name><filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class></filter><filter-mapping><filter-name>log4jServletFilter</filter-name><url-pattern>/*</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>ERROR</dispatcher></filter-mapping><!-- log4j2-end -->

注意

  • log4jConfiguration这个单词Log4j 2.x 以后改变了
  • 而且log4j2.xml 最好放在src/main/resources 根目录,否则可能会报找不到错误。

2.5 关于 MDC

我们知道在Log4j 1.x 中,MDC是一种多线程下日志管理实践方式,

关于用法主要用于获取多线程下的一些变量

  • 比如我们可以在代码中定义一个类Log4jServletContextListener 实现ServletContextListener接口
  • 然后获取多线程下的变量,比如上下文,IP地址等。

Log4j 1.x 实用MDC:

class Log4jServletContextListener implements ServletContextListener{@Overridepublic void contextInitialized(ServletContextEvent arg0) {// TODO Auto-generated method stubsuper.contextInitialized(arg0);InetAddress ia=null;try {//获取本地主机信息ia=InetAddress.getLocalHost();//获取请求的主机名称String localname=ia.getHostName();//获取请求的IP地址String localip=ia.getHostAddress();//获取应用程序的上下文String path = arg0.getServletContext().getContextPath();//格式化输出到日志MDC.put("ip", localip);MDC.put("path", path.substring(1));} catch (Exception e) {// TODO Auto-generated catch blocklog.error(e.getMessage(),e);}}
}

Log4j 2.x 则需要使用ThreadContext

Log4j2 升级后要实用ThreadContext 替换MDC

class Log4j2ServletContextListener implements ServletContextListener{@Overridepublic void contextInitialized(ServletContextEvent arg0) {// TODO Auto-generated method stubsuper.contextInitialized(arg0);InetAddress ia=null;try {//获取本地主机信息ia=InetAddress.getLocalHost();//获取请求的主机名称String localname=ia.getHostName();//获取请求的IP地址String localip=ia.getHostAddress();//获取应用程序的上下文String path = arg0.getServletContext().getContextPath();//格式化输出到日志ThreadContext.put("ip", localip);ThreadContext.put("path", path.substring(1));} catch (Exception e) {// TODO Auto-generated catch blocklog.error(e.getMessage(),e);}}
}

最后修改日志布局中就可以 用 %X{path} 和%X{ip} 来配置打印该内容

<PatternLayout charset="GB18030" pattern="%d{yyyy/MM/dd HH:mm:ss,SSS} %X{path} %X{ip} %-5level %l %n%msg%n"/>

2.6 Log4j 2.x 与Jboss 兼容性

当前 Jboss 版本 JBoss 6.4 (Jboss EAP 6.x)

15:08:32,192 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-4) JBAS015876: 开始 "******-1.0.war" 的部署(runtime-name: "******-1.0.war")
15:08:35,536 WARN  [org.jboss.as.server.deployment] (MSC service thread 1-3) JBAS015852: 无法对 META-INF/versions/9/module-info.class 里的类 /D:/apps/jboss-eap-6.4/bin/content/*******-1.0.war/WEB-INF/lib/log4j-api-2.11.0.jar 进行索引: java.lang.IllegalStateException: Unknown tag! pos=4 poolCount = 32at org.jboss.jandex.Indexer.processConstantPool(Indexer.java:665) [jandex-1.2.2.Final-redhat-1.jar:1.2.2.Final-redhat-1]at org.jboss.jandex.Indexer.index(Indexer.java:699) [jandex-1.2.2.Final-redhat-1.jar:1.2.2.Final-redhat-1]at org.jboss.as.server.deployment.annotation.ResourceRootIndexer.indexResourceRoot(ResourceRootIndexer.java:100) [jboss-as-server-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]at org.jboss.as.server.deployment.annotation.AnnotationIndexProcessor.deploy(AnnotationIndexProcessor.java:51) [jboss-as-server-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:159) [jboss-as-server-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1980) [jboss-msc-1.1.5.Final-redhat-1.jar:1.1.5.Final-redhat-1]at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1913) [jboss-msc-1.1.5.Final-redhat-1.jar:1.1.5.Final-redhat-1]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [rt.jar:1.8.0_144]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [rt.jar:1.8.0_144]at java.lang.Thread.run(Thread.java:748) [rt.jar:1.8.0_144]

2.6.1 问题分析

出现这个原因是log4j 2.x 版本太高不兼容 Jboss EAP 6.x.

2.6.2 解决方案

  • Log4j 2对JbossEAP 6.4 的兼容最高版本为2.9.1
  • Spring 5.x + 只支持 JBoss EAP 7.x+ 版本
  • Spring 4.3.29 是支持Jboss EAP 6.x 的最高版本

2.7 Jboss 6.x 不兼容Log4j 2.x 冲突问题

2.7.1 问题描述

经过测试JBoss6.x 不兼容 Log4j 2.x ,默认使用的是Log4j 1.x 的内容,可能会出现xml配置的日志输出不来的问题。

原因:Jboss 会自动在部署的应用上包裹一些日志模块

D:\apps\jboss-eap-6.4\modules\system\layers\base\org\apache\log4j\
D:\apps\jboss-eap-6.4\modules\system\layers\base\org\slf4j

2.7.2 解决方案

在WEB-INF根目录下,创建一个文件jboss-deployment-structure.xml
配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--JBoss 6.x 默认采用容器自己的log4j module,该模块是应用log4j 1.x,导致自己配置的log4j 2.x不起作用,因此需要应用做一些设置-->
<jboss-deployment-structure><deployment><!--排除掉Jboss自带的日志模块--><exclusions><module name="org.apache.log4j" /><module name="org.jboss.log4j.logmanager" /><module name="org.slf4j" /><module name="org.slf4j.impl" /><module name="org.slf4j.jcl-over-slf4j" /><module name="org.slf4j.ext" /><module name="ch.qos.cal10n" /><module name="org.jboss.logmanager" /></exclusions></deployment>
</jboss-deployment-structure>

log4j2.xml 最好 放到 src/main/resources根目录下
jboss-deployment-structure.xml 放到src/main/webapp/WEB-INF/ 根目录下

0x03 log4j 2.x XML配置和自定义线程日志

  • 关于log4j 2.xml 如何配置可以看下我的另一篇博文中的 XML配置篇
    关于log4j 2.x 自定义线程日志可以看下我的另一篇博文中的代码中自定义线程日志

0x04 参考博文

  • jboss7.1运行项目使用项目中的log4j打印日志
  • jboss7.1中配置log4j有效
  • Jboss log4j冲突分析与解决

本篇完~


喜欢我的博文,欢迎点赞和关注~

关于Log4j 1.x 升级Log4j 2.x 那些事相关推荐

  1. Log4j 1.x 升级 Log4j 2.x (调研和升级)

    因为公司业务需要,目前的log4j 1.x 遇到死锁,需要升级到Log4j 2.x.现在对目前的日志框架进行调研,并根据目前的现状提出升级的方法. 一引言 对于一个应用程序来说日志记录是必不可少的一部 ...

  2. Log4j使用详解(log4j.XML格式)——整理

    log4j.xml配置详解(原文地址) 首先当然是得到log4j的jar档,推荐使用1.2.X版,下载地址: http://logging.apache.org/log4j/1.2/download. ...

  3. log4j(七)——log4j.xml简单配置样例说明

    一:测试环境与log4j(一)--为什么要使用log4j?一样,这里不再重述 二:老规矩,先来个栗子,然后再聊聊感受 (1)这里栗子有一点特别呀!给出了包名唉!想必有用,是的,配置文件中要特别说明一下 ...

  4. Log4j使用详解(log4j.XML格式)

    首先当然是得到log4j的jar档,推荐使用1.2.X版,下载地址: http://logging.apache.org/log4j/1.2/download.html xml格式的log4j配置文件 ...

  5. 开发log4j配置_从 log4j 迁移到 logback

    最近把项目的日志框架从 log4j 迁移到 logback,过程里遇到很多坑,记录下来 目标 本次迁移的目标就是用 slf4j+logback 的日志框架来取代目前的 slf4j+log4j 如何迁移 ...

  6. java log4j 写日志_Java log4j同时写入文本日志和数据库日志

    版权声明:转载原创文章请以超链接形式请注明原文章出处,尊重作者,尊重原创! 恰饭广告 Log4jUtil.java import org.apache.log4j.Logger; import org ...

  7. log4j日志 linux配置,Log4j 日志详细用法

    简单的说log4j就是帮助开发人员进行日志输出管理的API类库.它最重要的特点就可以配置文件灵活的设置日志信息的优先级.日志信息的输出目的地.日志信息的输出格式 Log4j 除了可以记录程序运行日志信 ...

  8. log4j.dtd_Eclipse log4j.xml –无法将log4j.dtd验证为XML定义

    log4j.dtd I use log4j in most of the projects for logging and use XML based configuration. Most of t ...

  9. log4j的使用和log4j过时问题的解决

    log4j的使用和log4j过时问题的解决 1.添加依赖 在pom.xml文件中的<dependencies>下添加log4j依赖: <!--log4j 依赖--><de ...

  10. log4j(一)——什么是Log4j以及Log4j的体系结构

    一.什么是log4j 几乎每个大型应用程序都包含自己的日志或跟踪API.为了符合这一规则,欧盟SEMPRER项目决定编写自己的跟踪API.这是在1996年初.经过无数次的增强.几个版本和大量的工作之后 ...

最新文章

  1. 真正的在线教育,开始萌芽了
  2. docker安装redis提示没有日记写入权限_浅析Linux下Redis的攻击面(一)
  3. 2021-07-24
  4. boost::signals2模块thread_safe_signals 库替代线程模型的基本测试
  5. 基于netty访问WebSocket(java的websocket客户端)(访问远程ws协议)
  6. 登录样式:log4j 2,上下文,自动清除…全部不附加任何字符串!
  7. [css] 举例说明你对相邻兄弟选择器的理解
  8. 二下语文书电子课本_小学生语文成绩好,不是靠补课,把课本吃透,才是高效学习方法...
  9. 实战 | GitLab + Docker 实现多环境部署
  10. 安装默认报表服务器虚拟目录,报表服务器虚拟目录
  11. JAVA中解决Filter过滤掉css,js,图片文件等问题
  12. 一些编程习惯和问题记录--不定期更新
  13. CATIA二次开发:工程图中文本的遍历和修改
  14. Reading Ingestion —— Paxos Made Simple
  15. python分段函数编写程序_python分段函数如何编写?
  16. 微信的转账记录删除了还能恢复吗?2个办法教你找回
  17. 排列组合———求一串数字可以有多少种不同的组合
  18. 公司招了个五年经验的测试员,见识到了真正的测试天花板
  19. Android打包混淆压缩
  20. 着色器Encoding floats to RGBA

热门文章

  1. 苹果退款_这里有颗“后悔药”:苹果App Store退款流程
  2. jvm-垃圾回收(垃圾收集器)
  3. SEO为什么一定要面面俱到?
  4. oracle excel导入卡死 新解决办法
  5. 【操作系统】进程间通信 — 消息队列
  6. 基础软件“好用”指南:必须跨越这两道鸿沟!
  7. create table
  8. android模拟器 vm版,怎样用vmware虚拟机安装android模拟器
  9. Servlet(互联网通信基础及实例)(上)
  10. Prolog入门教程