问题描述
我正在尝试将我的应用迁移到使用log4j2中.它目前正在使用log4j 1.2.16.我的项目也有一个性能构建,在升级到log4j 2之后,性能似乎有所提高.
也就是说,直到我阅读有关桥接的内容.根据DOC的说法,我必须将Log4J1 Jar从类Pather排除,并包括桥接JAR-我认为该jar命名为'org.apache.logging.log4j:log4j-1.2-api'.一旦我这样做,性能再次下降.
所以总结:
- log4j2 +桥接jar + log4j-1.2-api + log4j1的性能:好
- log4j2 +桥接jar + log4j-1.2-api的性能:糟糕(以至于它落后于log4j1的性能)
我已经检查了log4j-1.2-api在类路径中较早.因此,应该先加载它.
知道什么可能导致这个问题?
非常感谢您!
哦,我的完整登录路径是:
- org.slf4j:slf4j-api
- org.slf4j:log4j-over-slf4j
- org.slf4j:jcl-over-slf4j
- org.apache.logging.log4j:log4j-slf4j-impl
- org.apache.logging.log4j:log4j-core
- org.apache.logging.log4j:log4j-api
- org.apache.logging.log4j:log4j-1.2-api
- log4j:log4j(如上所述,有和不带)
版本:
- log4j2:2.6.2
- SLF4J:1.7.20
- log4j1:1.2.16
我的配置文件看起来像:
<?xml version="1.0" encoding="UTF-8"?> <Configuration xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="log4j2-xinclude-appenders.xml" /> <Loggers> <Root level="info"> <AppenderRef ref="rollingFileAppender"/> <AppenderRef ref="stdOutAppender"/> </Root> </Loggers> </Configuration>
和log4j2-xinclude-appenders.xml看起来像:
<?xml version="1.0" encoding="UTF-8"?> <appenders> <RollingRandomAccessFile name="_rollingFileAppender" fileName="./logs/foo-${sys:app.name.suffix}.log" filePattern="./logs/foo-${sys:foo.app.name.suffix}.log.%i"> <PatternLayout> <Pattern>%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n</Pattern> </PatternLayout> <Policies> <OnStartupTriggeringPolicy minSize="0" /> <SizeBasedTriggeringPolicy size="100 MB" /> </Policies> <DefaultRolloverStrategy max="10"/> </RollingRandomAccessFile> <Async name="rollingFileAppender" blocking="false" bufferSize="10000"> <AppenderRef ref="_rollingFileAppender"/> </Async> <Console name="_stdOutAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n"/> </Console> <Async name="stdOutAppender" blocking="false" bufferSize="10000"> <AppenderRef ref="_stdOutAppender"/> </Async> </appenders>
编辑:这是log4j 1 xml文件,该文件包含在classPath中
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="A1" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <appender name="R" class="com.bar.common.util.RollingFileAppender"> <param name="File" value="./logs/bar.log"/> <param name="MaxFileSize" value="100MB"/> <param name="MaxBackupIndex" value="10"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <!-- Performance Appender --> <appender name="OneSecondStatsAppender" class="com.foo.perf.AggregatedStatisticsAppender"> <param name="TimeSlice" value="1000"/> <appender-ref ref="OneSecondStatsLogger"/> </appender> <appender name="FiveMinuteStatsAppender" class="com.bar.perf.DatafabricAggregatedStatisticsAppender"> <param name="TimeSlice" value="300000"/> <appender-ref ref="FiveMinuteStatsLogger"/> </appender> <!-- Aggregated Performance Statistics Appender --> <appender name="OneSecondStatsLogger" class="org.apache.log4j.FileAppender"> <param name="File" value="./logs/bar-performance.log"/> <layout class="com.bar.perf.AggregatedStatisticsCsvLayout"/> <filter class="com.bar.perf.CategorisedStatisticExclusionFilter"/> </appender> <appender name="FiveMinuteStatsLogger" class="org.apache.log4j.FileAppender"> <param name="File" value="./logs/bar-minutes.log"/> <layout class="com.bar.perf.AggregatedStatisticsCsvLayout"> <param name="ShowEmptyStatistics" value="true"/> </layout> </appender> <!-- Loggers --> <logger name="org.perf4j.TimingLogger" additivity="false"> <level value="INFO"/> <appender-ref ref="OneSecondStatsAppender"/> <appender-ref ref="FiveMinuteStatsAppender"/> </logger> <logger name="com.bar"> <level value="INFO"/> </logger> <logger name="com.gemstone.gemfire"> <level value="INFO"/> </logger> <logger name="org.springframework.data"> <level value="INFO"/> </logger> <!-- Root logger configuration --> <root> <priority value="INFO"/> <appender-ref ref="R"/> </root> </log4j:configuration>
编辑2 : 表现不佳的班级订单:
log4j-1.2-api-2.6.2.jar jcl-over-slf4j-1.7.20.jar slf4j-api-1.7.20.jar log4j-slf4j-impl-2.6.2.jar log4j-core-2.6.2.jar log4j-api-2.6.2.jar log4j-1.2.16.jar
良好性能的班级路径订单
log4j-1.2-api-2.6.2.jar jcl-over-slf4j-1.7.20.jar slf4j-api-1.7.20.jar log4j-over-slf4j-1.7.20.jar log4j-slf4j-impl-2.6.2.jar log4j-core-2.6.2.jar log4j-api-2.6.2.jar log4j-1.2.16.jar
推荐答案
i这里有两个问题:
- 为什么log4j 1在某些classpath配置中使用
- 为什么log4j 2不快于log4j 1
1.为什么使用log4j 1
我怀疑以下SLF4J依赖性导致使用旧的log4j 1.2:
org.slf4j:log4j-over-slf4j org.slf4j:jcl-over-slf4j
如果使用maven,即使您不在POM中明确声明它,这些也可能会将旧的log4j 1作为及其依赖性.
请删除这些. Log4j 2具有Log4J-SLF4J-IMPL和LOG4J-JCL模块,这些模块将完成相同但使用Log4J 2.
您不应在类路径中使用log4j 1.如果您的应用程序(或您使用的任何库)取决于Log4J 1 API,则添加Log4J-1.2-API模块.
2.为什么log4j 2不快于log4j 1
您描述的配置不会利用Log4J 2功能.它使用异步(在log4j 1和2中大致等效)和consoleappender(在log4j 2中稍差). consoleappender consoleappender比文件Appender慢60倍.登录生产系统中的控制台时要非常小心.
这是我建议的:删除以下内容(现在似乎可以提供更好的表现,但要忍受我)
- log4j-over-slf4j-1.7.20
- log4j-1.2.16
- 旧的lo4j.xml配置
添加 lmax破坏者依赖性:
<!-- https://mvnrepository.com/artifact/com.lmax/disruptor --> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.2.0</version> </dependency>
使用以下log4j2.xml配置.暂时将其制成一个简单的文件而不包含,您可以稍后将其放回. (请注意,我将<Configuration status="trace"添加到文件的开头:将输出内部log4j2调试语句,以便您可以确认配置完成而不会出现问题.)
请注意,我怀疑它会影响性能.
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="TRACE" xmlns:xi="http://www.w3.org/2001/XInclude"> <appenders> <RollingRandomAccessFile name="_rollingFileAppender" fileName="./logs/foo-${sys:app.name.suffix}.log" filePattern="./logs/foo-${sys:foo.app.name.suffix}.log.%i"> <PatternLayout> <Pattern>%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n</Pattern> </PatternLayout> <Policies> <OnStartupTriggeringPolicy minSize="0" /> <SizeBasedTriggeringPolicy size="100 MB" /> </Policies> <DefaultRolloverStrategy max="10"/> </RollingRandomAccessFile> <Console name="_stdOutAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n"/> </Console> </appenders> <Loggers> <Root level="info"> <AppenderRef ref="_rollingFileAppender"/> <AppenderRef ref="_stdOutAppender" level="WARN" /> </Root> </Loggers> </Configuration>
现在,最终(键)点:启用log4j 2 async loggers 通过将系统属性Log4jContextSelector设置为org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.
这最后一位应该会带来很大的性能. (以及禁用控制台记录.)
其他推荐答案
我遇到了更奇怪的发现.我启用了' - verbose:类'JVM选项以查看加载哪个类,我可以确认仅加载了以下罐子中的类(按顺序):
- slf4j-api-1.7.20.jar
- log4j-slf4j-impl-2.6.2.jar
- log4j-api 2.6.2.jar
- log4j-core-2.6.2.jar
- log4j-1.2-api 2.6.2.2.jar
- jcl-over-slf4j-1.7.20.jar
然而,以下两个测试产生不同的结果:
- 性能测试,其中包括log4j-over-SLF4J-1.7.20&log4j-1.2.16: 好
- 性能测试,其中包括log4j-over-slf4j-1.7.20&但不包括log4j-1.2.16:bad
- 不排除log4j-over-SLF4J-1.7.20&包括log4j-1.2.16的性能测试:不良
请注意,这两个罐子根本没有加载.
问题描述
I'm trying to migrate my app into using log4j2. It is currently using log4j 1.2.16. I also have a performance build for my project, and after upgrading to log4j 2, the performance seemed to have improve a lot.
That is, until I read about bridging. According to the doc, I have to exclude log4j1 JAR from the classpath, and include the bridging JAR - which I assume is named 'org.apache.logging.log4j:log4j-1.2-api'. Once I did this, performance dropped again.
So to summarise:
- Performance with log4j2 + bridging jar + log4j-1.2-api + log4j1 : good
- Performance with log4j2 + bridging jar + log4j-1.2-api : bad (to the point that it drops back to performance of just log4j1)
I have checked that the log4j-1.2-api is earlier in the classpath. So it should have been loaded first.
Any idea what could cause this problem?
Thank you very much in advance!
Oh my complete classpath for logging are:
- org.slf4j:slf4j-api
- org.slf4j:log4j-over-slf4j
- org.slf4j:jcl-over-slf4j
- org.apache.logging.log4j:log4j-slf4j-impl
- org.apache.logging.log4j:log4j-core
- org.apache.logging.log4j:log4j-api
- org.apache.logging.log4j:log4j-1.2-api
- log4j:log4j (with & without, as described above)
Versions:
- Log4j2 : 2.6.2
- slf4j: 1.7.20
- log4j1: 1.2.16
My config file looks like:
<?xml version="1.0" encoding="UTF-8"?> <Configuration xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="log4j2-xinclude-appenders.xml" /> <Loggers> <Root level="info"> <AppenderRef ref="rollingFileAppender"/> <AppenderRef ref="stdOutAppender"/> </Root> </Loggers> </Configuration>
And the log4j2-xinclude-appenders.xml looks like:
<?xml version="1.0" encoding="UTF-8"?> <appenders> <RollingRandomAccessFile name="_rollingFileAppender" fileName="./logs/foo-${sys:app.name.suffix}.log" filePattern="./logs/foo-${sys:foo.app.name.suffix}.log.%i"> <PatternLayout> <Pattern>%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n</Pattern> </PatternLayout> <Policies> <OnStartupTriggeringPolicy minSize="0" /> <SizeBasedTriggeringPolicy size="100 MB" /> </Policies> <DefaultRolloverStrategy max="10"/> </RollingRandomAccessFile> <Async name="rollingFileAppender" blocking="false" bufferSize="10000"> <AppenderRef ref="_rollingFileAppender"/> </Async> <Console name="_stdOutAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n"/> </Console> <Async name="stdOutAppender" blocking="false" bufferSize="10000"> <AppenderRef ref="_stdOutAppender"/> </Async> </appenders>
EDIT: This is the log4j 1 xml file that gets included in the classpath
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="A1" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <appender name="R" class="com.bar.common.util.RollingFileAppender"> <param name="File" value="./logs/bar.log"/> <param name="MaxFileSize" value="100MB"/> <param name="MaxBackupIndex" value="10"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <!-- Performance Appender --> <appender name="OneSecondStatsAppender" class="com.foo.perf.AggregatedStatisticsAppender"> <param name="TimeSlice" value="1000"/> <appender-ref ref="OneSecondStatsLogger"/> </appender> <appender name="FiveMinuteStatsAppender" class="com.bar.perf.DatafabricAggregatedStatisticsAppender"> <param name="TimeSlice" value="300000"/> <appender-ref ref="FiveMinuteStatsLogger"/> </appender> <!-- Aggregated Performance Statistics Appender --> <appender name="OneSecondStatsLogger" class="org.apache.log4j.FileAppender"> <param name="File" value="./logs/bar-performance.log"/> <layout class="com.bar.perf.AggregatedStatisticsCsvLayout"/> <filter class="com.bar.perf.CategorisedStatisticExclusionFilter"/> </appender> <appender name="FiveMinuteStatsLogger" class="org.apache.log4j.FileAppender"> <param name="File" value="./logs/bar-minutes.log"/> <layout class="com.bar.perf.AggregatedStatisticsCsvLayout"> <param name="ShowEmptyStatistics" value="true"/> </layout> </appender> <!-- Loggers --> <logger name="org.perf4j.TimingLogger" additivity="false"> <level value="INFO"/> <appender-ref ref="OneSecondStatsAppender"/> <appender-ref ref="FiveMinuteStatsAppender"/> </logger> <logger name="com.bar"> <level value="INFO"/> </logger> <logger name="com.gemstone.gemfire"> <level value="INFO"/> </logger> <logger name="org.springframework.data"> <level value="INFO"/> </logger> <!-- Root logger configuration --> <root> <priority value="INFO"/> <appender-ref ref="R"/> </root> </log4j:configuration>
EDIT 2: Classpath order for poor performance:
log4j-1.2-api-2.6.2.jar jcl-over-slf4j-1.7.20.jar slf4j-api-1.7.20.jar log4j-slf4j-impl-2.6.2.jar log4j-core-2.6.2.jar log4j-api-2.6.2.jar log4j-1.2.16.jar
Classpath order for good performance
log4j-1.2-api-2.6.2.jar jcl-over-slf4j-1.7.20.jar slf4j-api-1.7.20.jar log4j-over-slf4j-1.7.20.jar log4j-slf4j-impl-2.6.2.jar log4j-core-2.6.2.jar log4j-api-2.6.2.jar log4j-1.2.16.jar
推荐答案
I there there are two questions here:
- Why does log4j 1 get used in certain classpath configurations
- Why is log4j 2 not faster than log4j 1
1. Why is log4j 1 used
I suspect that the following slf4j dependencies caused the old log4j 1.2 to be used:
org.slf4j:log4j-over-slf4j org.slf4j:jcl-over-slf4j
If you use maven these could bring in the old Log4j 1 as a transitive dependency even if you don't explicitly declare it in your POM.
Please remove these. Log4j 2 has log4j-slf4j-impl and log4j-jcl modules that will accomplish the same but use Log4j 2 instead.
You should not have Log4j 1 in the classpath. If your application (or any of the libraries you use) depend on the Log4j 1 API, then add the log4j-1.2-api module.
2. Why is log4j 2 not faster than log4j 1
The configuration you describe does not take advantage of log4j 2 features. It uses AsyncAppender (which is roughly equivalent in log4j 1 and 2) and ConsoleAppender (which is slightly worse in log4j 2). ConsoleAppender is about 60 times slower than file appender. Be extremely careful when logging to the console in production systems.
Here is what I suggest: remove the following (which now seems to give better performance, but bear with me)
- log4j-over-slf4j-1.7.20
- log4j-1.2.16
- the old lo4j.xml configuration
Add the LMAX Disruptor dependency:
<!-- https://mvnrepository.com/artifact/com.lmax/disruptor --> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.2.0</version> </dependency>
Use the following log4j2.xml configuration. Temporarily just make it a simple file without includes, you can put that back later. (Notice I added <Configuration status="trace" to the beginning of the file: that will output internal log4j2 debugging statements so you can confirm that configuration completed without problems.)
Note that I made Console logging WARN level as I suspect it is impacting performance.
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="TRACE" xmlns:xi="http://www.w3.org/2001/XInclude"> <appenders> <RollingRandomAccessFile name="_rollingFileAppender" fileName="./logs/foo-${sys:app.name.suffix}.log" filePattern="./logs/foo-${sys:foo.app.name.suffix}.log.%i"> <PatternLayout> <Pattern>%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n</Pattern> </PatternLayout> <Policies> <OnStartupTriggeringPolicy minSize="0" /> <SizeBasedTriggeringPolicy size="100 MB" /> </Policies> <DefaultRolloverStrategy max="10"/> </RollingRandomAccessFile> <Console name="_stdOutAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d|%X{active.profiles}| %-5p |%X{fcp.session}|%X{StateMachine.key}|%X{StateMachine.currentState}| %m | %t | %c{1.}%n"/> </Console> </appenders> <Loggers> <Root level="info"> <AppenderRef ref="_rollingFileAppender"/> <AppenderRef ref="_stdOutAppender" level="WARN" /> </Root> </Loggers> </Configuration>
Now, the final (key) point: enable log4j 2 async loggers by setting system property Log4jContextSelector to org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.
This last bit should make a large performance difference. (Together with disabling Console logging.)
其他推荐答案
I ran into more strange findings. I enabled '-verbose:class' JVM options to see which classes were loaded, and I can confirm that only classes from the following JARs were loaded (in the order):
- slf4j-api-1.7.20.jar
- log4j-slf4j-impl-2.6.2.jar
- log4j-api-2.6.2.jar
- log4j-core-2.6.2.jar
- log4j-1.2-api-2.6.2.jar
- jcl-over-slf4j-1.7.20.jar
Yet, the following two tests yield different result:
- Performance test with including log4j-over-slf4j-1.7.20 & log4j-1.2.16 : GOOD
- Performance test with including log4j-over-slf4j-1.7.20 & but excluding log4j-1.2.16 : BAD
- Performance test with excluding log4j-over-slf4j-1.7.20 & including log4j-1.2.16 : BAD
Note that these two JARs were not loaded at all.