log4j:log4j1.x升级log4j2.x及异步日志开启

    由于log4j1.x采用同步的方式打印log,当项目中打印log的地方很多的时候,频繁的加锁拆锁会导致性能的明显下降。log4j推出了异步logging的方式,所以项目准备升级log4j2.x。

    备注:项目使用maven管理第三方类库,所以jar包的替换是通过更改maven配置的方式进行更改的。

    官方文档链接:https://logging.apache.org/log4j/2.x/manual/migration.html

1、升级jar包

    需要将原来的log4j的jar包替换成log4j2.x的相关jar包。在maven的pom.xml文件中修改依赖:

原依赖(需要删除):

<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.14</version>
</dependency>

新依赖:

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-api</artifactId>
  <version>「版本号,例如:2.11.1」</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>「版本号,例如:2.11.1」</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-1.2-api</artifactId>
  <version>「版本号,例如:2.11.1」</version>
</dependency>

注意:log4j-api和log4j-core是必须的核心包,log4j-1.2-api是官方推出的平稳的过度包。

Perhaps the simplest way to convert to using Log4j 2 is to replace the log4j 1.x jar file with Log4j 2's log4j-1.2-api.jar. However, to use this successfully applications must meet the following requirements:

  1. They must not access methods and classes internal to the Log4j 1.x implementation such as Appenders, LoggerRepository or Category's callAppenders method.
  2. They must not programmatically configure Log4j.
  3. They must not configure by calling the classes DOMConfigurator or PropertyConfigurator.

2、升级api

    关键的API需要切换的有:

1)包名:org.apache.log4j替换为org.apache.logging.log4j

2)Logger实例的获取方式:org.apache.log4j.Logger.getLogger() 替换为org.apache.logging.log4j.LogManager.getLogger();

3)MDC/NDC:替换成ThreadContext;

4)Logger等级Level的set和get:参照如下官方文档的描述进行替换

5)LogManager.shutdown():新版本中增加了自动关闭的功能,也可以参照如下官方文档第6条进行手动关闭。

官方文档:

For the most part, converting from the Log4j 1.x API to Log4j 2 should be fairly simple. Many of the log statements will require no modification. However, where necessary the following changes must be made.

  1. The main package in version 1 is org.apache.log4j, in version 2 it is org.apache.logging.log4j
  2. Calls to org.apache.log4j.Logger.getLogger() must be modified to org.apache.logging.log4j.LogManager.getLogger().
  3. Calls to org.apache.log4j.Logger.getRootLogger() or org.apache.log4j.LogManager.getRootLogger() must be replaced withorg.apache.logging.log4j.LogManager.getRootLogger().
  4. Calls to org.apache.log4j.Logger.getLogger that accept a LoggerFactory must remove the org.apache.log4j.spi.LoggerFactory and use one of Log4j 2's other extension mechanisms.
  5. Replace calls to org.apache.log4j.Logger.getEffectiveLevel() with org.apache.logging.log4j.Logger.getLevel().
  6. Remove calls to org.apache.log4j.LogManager.shutdown(), they are not needed in version 2 because the Log4j Core now automatically adds a JVM shutdown hook on start up to perform any Core clean ups.
    1. Starting in Log4j 2.1, you can specify a custom ShutdownCallbackRegistry to override the default JVM shutdown hook strategy.
    2. Starting in Log4j 2.6, you can now use org.apache.logging.log4j.LogManager.shutdown() to initiate shutdown manually.
  7. Calls to org.apache.log4j.Logger.setLevel() or similar methods are not supported in the API. Applications should remove these. Equivalent functionality is provided in the Log4j 2 implementation classes, see org.apache.logging.log4j.core.config.Configurator.setLevel(), but may leave the application susceptible to changes in Log4j 2 internals.
  8. Where appropriate, applications should convert to use parameterized messages instead of String concatenation.
  9. org.apache.log4j.MDC and org.apache.log4j.NDC have been replaced by the Thread Context.

3、升级配置文件

    Log4j2中,在版本2.4及以后开始支持.properties格式的配置文件,但是在实际使用中感觉2.4和2.4.1版本配置.properties后没有实际上生效,更换2.6版本后该问题解决。如下提供了简单的配置文件升级对应的示例。

简单配置升级示例:

log4j 1.x版本配置文件:

log4j.rootLogger=info, R, stdout
log4j.logger.org.apache.hadoop=OFF

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n - %L

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=logs/context.log
log4j.appender.R.MaxFileSize=20000KB
log4j.appender.R.MaxBackupIndex=3
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d [%t] %-5p %c - %m%n - %L

升级后对应的配置文件:

status=INFO
name=PropertiesConfig
rootLogger.level=INFO
rootLogger.appenderRef.R.ref=R
rootLogger.appenderRef.stdout.ref=stdout
appender.R.type=RollingFile
appender.R.name=R
appender.R.fileName=logs/context.log
appender.R.filePattern=logs/context.log-%d{dd}-%i.log
appender.R.layout.type=PatternLayout
appender.R.layout.pattern=%d [%t] %-5p %c - %m%n - %L
appender.R.strategy.type=DefaultRolloverStrategy
appender.R.strategy.max=3
appender.R.policies.type=policies
appender.R.policies.size.type=SizeBasedTriggeringPolicy
appender.R.policies.size.size=20000KB
appender.stdout.type=Console
appender.stdout.name=stdout
appender.stdout.layout.type=PatternLayout
appender.stdout.layout.pattern=%d [%t] %-5p %c - %m%n - %L
logger.hadoop.name=org.apache.hadoop
logger.hadoop.level=OFF

 

4、升级加载指定配置文件的方式

    在log4j1.x的版本中,可以通过DOMConfigurator或PropertyConfigurator来加载制定的配置文件,但是升级2.x后该API不可用。可以通过Configurator的静态方法initializ来初始化log4j2。

代码示例:

URL url = Main.class.getClassLoader().getResource("config/log4j.properties");
ConfigurationSource source = null;
try {
  source = new ConfigurationSource(url.openStream(), url);
  Configurator.initialize(null, source);
} catch (IOException e) {
  e.printStackTrace();
}

备注:ConfigurationSource有很多个构造器,可以在不同情况下使用不同的构造器来加载配置文件。

5、开启异步日志

    Log4j2.x的异步日志有两种实现方式:全局异步方式和混合异步方式。其中,全局异步方式实现起来操作更简单、性能提升的更明显。此处以全局异步的配置为例。

1)添加依赖

    首先,需要给项目添加disruptor的jar包,log4j2.9以及2.9以上,需要添加disruptor-3.3.4.jar或以上版本;低于log4j2.9的情况下,添加 disruptor-3.0.0.jar 及以上版本即可。

    参考官方文档:Log4j-2.9 and higher require disruptor-3.3.4.jar or higher on the classpath. Prior to Log4j-2.9, disruptor-3.0.0.jar or higher was required.

    maven项目的添加方式:在模块的pom.xml文件中添加disruptor的依赖,log4j 2.9及以上版本要求disruptor的版本在3.3.4以上。maven的官方库链接:https://mvnrepository.com/artifact/com.lmax/disruptor/3.3.4

<!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
<dependency>
  <groupId>com.lmax</groupId>
  <artifactId>disruptor</artifactId>
  <version>3.3.4</version>
</dependency>

2)配置系统变量

    然后,只需要配置系统变量Log4jContextSelector的值为org.apache.logging.log4j.core.async.AsyncLoggerContextSelector,即可开启全局异步日志打印功能。

    参考官方文档:To make all loggers asynchronous, add the disruptor jar to the classpath and set the system property log4j2.contextSelector to org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.

配置系统变量Log4jContextSelector有两种方式:

方式一:log4j2会自动在resource下加载log4j2.component.properties文件,使用可以在resources路径下创建文件并命名为log4j2.component.properties,添加如下内容,配置该系统变量:

Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

方式二:配置JVM的启动参数,在启动命令中添加如下参数:

-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

上述参数可以在命令行执行java命令时添加,也可以在使用ide运行的情况下,在启动配置中进行配置。

6、踩坑记录

1)版本问题:2.4以后开始支持.properties配置文件,但是实践发现2.4和2.4.1使用.properties文件后,会去寻找该文件,但是配置的信息是有问题的,出现了无法打印log的问题,升级版本到2.6之后问题解决;

2)外部引用的库调用log4j1.x的问题:无法解决,引入了过度包,让它们继续使用1.x,此时使用log4j1.x的外部库是无法使用log4j2的配置的。

3)配置文件的配置中,log4g1.x中有些size based RollingFile没有配置filePattern,但是升级后如果配置filePattern就会报错。

4)在运行jar包的情况下,如果需要加载指定的配置文件,这时如果选用的ConfigurationSource的构造器的参数包含File,并且该File文件位于jar包内部,那么log4j2的初始化就有可能会失败,因为java无法通过new File()的方式去访问jar包内部的文件,这是由于java会把jar文件视为一个文件,而不是一个目录。这时可以通过ClassLoader的getResource方法去获取该文件的URL,然后通过url.openStream打开输入流,使用含InputStream参数的ConfigurationSource构造器。详情可以参考第4步的实例。

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页