2016-09-28 3 views
0

Я пытаюсь перенести свое приложение на использование log4j2. В настоящее время используется log4j 1.2.16. У меня также есть производительность для моего проекта, и после обновления до log4j 2 производительность, похоже, значительно улучшилась.Производительность log4j2 по сравнению с log4j1

То есть, пока я не прочитал про мост. Согласно документу, я должен исключить log4j1 JAR из пути к классам и включить мостовой JAR, который, как я предполагаю, называется «org.apache.logging.log4j: log4j-1.2-api». Как только я это сделал, производительность снова упала.

Итак, подведет итог:

  1. Производительности с log4j2 + преодолением баночки + log4j-1.2-апи + log4j1: хороший
  2. Performance с log4j2 + преодолением баночки + log4j-1.2-апи: плохо (к что он возвращается к производительности только log4j1)

Я проверил, что log4j-1.2-api ранее в пути к классам. Поэтому он должен был быть загружен первым.

Любая идея, что может вызвать эту проблему?

спасибо, что заблаговременно!

О мой полный путь к классам для регистрации являются:

  • org.slf4j: SLF4J-апи
  • org.slf4j: log4j-над-SLF4J
  • org.slf4j: JCL-над-SLF4J
  • org.apache.logging.log4j: log4j-SLF4J-осущ
  • org.apache.logging.log4j: log4j-жильный
  • org.apache.logging.log4j: log4j-апи
  • org.apache.logging.log4j: log4j-1,2-апи
  • 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> 

EDIT: Это XML-файл log4j 1, который получает включены в путь к классам

<?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 порядка для плохой работы:

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 
+0

Когда вы говорите «мостиковая банка + log4j-1.2-api», что вы имеете в виду? Разве это не одно и то же? –

+0

Точно. Они одинаковые. Но в документации log4j 2 указано «мостовая банка»: https://logging.apache.org/log4j/log4j-2.1/log4j-1.2-api/index.html. Сначала меня тоже смущали! –

+0

Привет, я хотел бы знать, как вы протестировали производительность приложения. Какие параметры вы рассматривали и зачем вам нужен log4j-over-slf4j-1.7.20. –

ответ

0

я там есть два вопроса:

  1. Почему log4j 1 привыкают в некоторых конфигурациях путь к классам
  2. Почему log4j 2 не быстрее, чем log4j 1

1 . Почему используется log4j 1

Я подозреваю, что следующий slf4 J зависимости вызвали старый log4j 1,2 будет использоваться:

org.slf4j:log4j-over-slf4j 
org.slf4j:jcl-over-slf4j 

Если вы используете Maven это может принести в старом Log4j-как переходная зависимость, даже если вы явно не объявить его в POM.

Удалите их. Log4j 2 имеет модули log4j-slf4j-impl и log4j-jcl, которые будут выполнять то же самое, но вместо этого использовать Log4j 2.

У вас не должно быть Log4j 1 в пути к классам. Если ваше приложение (или любая из используемых вами библиотек) зависит от API Log4j 1, добавьте модуль log4j-1.2-api.

2. Почему log4j 2 не быстрее, чем log4j 1

Конфигурация вы описываете не воспользоваться log4j 2 функциями. Он использует AsyncAppender (который примерно эквивалентен в log4j 1 и 2) и ConsoleAppender (что немного хуже в log4j 2). ConsoleAppender is about 60 times slower, чем файл appender. Будьте предельно осторожны при входе в консоль в производственных системах.

Вот что я предлагаю: удалить следующее (который теперь, кажется, дает более высокую производительность, но иметь со мной)

  • log4j-над-SLF4J-1.7.20
  • log4j-1,2 +0,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, чтобы вы могли подтвердить, что конфигурация завершена без проблем.)

Обратите внимание, что я сделал консольный журнал WARN уровня, поскольку я подозреваю, что это влияет на производительность.

<?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.

Этот последний бит должен иметь большую разницу в производительности. (Вместе с отключением ведомости консоли.)

+0

Привет Ремко. Я могу попытаться удалить их. Однако, когда я включаю log4j 1 JAR, производительность была намного лучше. Итак, как я уже упоминал, мое приложение последовательно работает лучше с log4j-1.2-api _plus_ log4j1 JAR. Довольно верно, что log4j-1.2-api используется, поскольку он указан ранее в пути к классам. Я также проверил, какой класс Logger используется, и я могу подтвердить, что тот, который используется в log4j-1.2.api, используется. Однако .. этот JAR не содержит всех классов из log4j 1 JAR. Что заставляет меня задаться вопросом, есть ли где-нибудь какие-то «оставшиеся» классы. –

+0

Можете ли вы показать свой файл конфигурации ведения журнала? –

+0

Еще раз спасибо Ремко. Я редактировал свое оригинальное сообщение, чтобы включить их. –

0

Я столкнулся с более странными выводами. Я включил «-verbose: класс» параметры виртуальной машины Java, чтобы увидеть, какие классы были загружены, и я могу подтвердить, что были загружены только классы из следующих JAR-файлов (в произвольном порядке):

  • SLF4J-Апи-1.7.20. банку
  • log4j-SLF4J-осущ-2.6.2.jar
  • log4j-апи-2.6.2.jar
  • log4j-ядро-2.6.2.jar
  • log4j-1,2-апи-2.6. 2.jar
  • jcl-over-slf4j-1.7.20.jar

Тем не менее, следующие два теста дают разный результат:

  1. тест производительности с включением log4j-над-SLF4J-1.7.20 & log4j-1.2.16: ХОРОШО
  2. Тест производительности с включением log4j- над-SLF4J-1.7.20 & но исключая log4j-1.2.16: BAD
  3. тест производительности с исключением log4j-над-SLF4J-1.7.20 & включая log4j-1.2.16: BAD

Обратите внимание, что эти два JAR не были загружены вообще.

Смежные вопросы