简体   繁体   English

Log4J2配置失败:具有Spring-AMQP / Spring-Rabbit的Log4J2 RabbitMQ Appender

[英]Log4J2 Configuration fails: Log4J2 RabbitMQ Appender with Spring-AMQP/Spring-Rabbit

I'm trying to integrate a Log4J2 Appender to RabbitMQ in an already working and logging java application. 我正在尝试将Log4J2 Appender集成到已经工作且正在记录Java应用程序的RabbitMQ中。

The application is build as a gradle project. 该应用程序是作为gradle项目构建的。 Before the integration of spring-rabbit, the build.gradle file looked like this: 在集成spring-rabbit之前, build.gradle文件如下所示:

group 'Name'
version '1.18.7'

apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    [...]
    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
    compile group: 'com.lmax', name: 'disruptor', version: '3.3.7'
    [...]
}

jar {
    manifest {
        attributes 'Main-Class': 'the.main.Clazz'
    }
}


buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath group: 'com.github.jengelman.gradle.plugins', name: 'shadow', version: '2.0.2'
    }
}

The log4j2.xml file, positioned in the src/resources folder, contains this (before rabbitMQ): 位于src/resources文件夹中的log4j2.xml文件包含以下内容(在RabbitMQ之前):

<?xml version="1.0" encoding="UTF-8"?>

<Configuration monitorInterval="15">
    <Appenders>
        <Console name="STDOUT">
            <PatternLayout>
                <Pattern>%d [%highlight{%-6p}{STYLE=DEFAULT, noConsoleNoAnsi=true}] %C{1}.%M(%F:%L) - %m%n%throwable</Pattern>
            </PatternLayout>
        </Console>
        <RandomAccessFile name="ASYNC_FILE" fileName="logs/app.log" immediateFlush="false" append="true">
            <PatternLayout>
                <Pattern>%d [%-6p] %C{1}.%M(%F:%L) - %m%n%throwable</Pattern>
            </PatternLayout>
        </RandomAccessFile>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="STDOUT"/>
        </Root>
        <Logger name="my.package" level="info" additivity="false">
            <AppenderRef ref="ASYNC_FILE"/>
        </Logger>
    </Loggers>
</Configuration>

The application runs nicely, as well as from the IDE and the JAR, built with the shadowJar plugin. 该应用程序以及通过shadowJar插件构建的IDE和JAR都可以很好地运行。

Now, the mystery begins. 现在,谜团开始了。 Simply by adding the spring-rabbit dependency... 只需添加spring-rabbit依赖关系...

compile group: 'org.springframework.amqp', name: 'spring-rabbit', version: '2.0.2.RELEASE'

...logging starts to behave very strange. ...记录开始变得非常奇怪。 Started from the IDE, everything works still nice. 从IDE开始,一切仍然正常。 Adding the following appender to the log4j2.xml works fine: 将以下附加程序添加到log4j2.xml可以正常工作:

    <RabbitMQ name="RABBIT_MQ"
              host="my.host.name" port="5672" user="logger" password="logger" virtualHost="loggerhost"
              exchange="logs" exchangeType="fanout" declareExchange="false"
              applicationId="app-xyz" routingKeyPattern="%X{applicationId}.%c.%p"
              contentType="text/plain" contentEncoding="UTF-8" generateId="true" deliveryMode="NON_PERSISTENT"
              charset="UTF-8"
              senderPoolSize="3" maxSenderRetries="5">
        <PatternLayout>
            <Pattern>%d [%-6p] %C{1}.%M(%F:%L) - %m%n%throwable</Pattern>
        </PatternLayout>
    </RabbitMQ>

I see the log messages delivered via the RabbitMQ server. 我看到通过RabbitMQ服务器传递的日志消息。

But when I build and run the JAR file built with :shadowJar , logging stops working. 但是,当我构建并运行使用:shadowJar构建的JAR文件时,日志记录将停止工作。 On STDOUT, I see the following: 在STDOUT上,我看到以下内容:

ERROR StatusLogger Unrecognized format specifier [d]
ERROR StatusLogger Unrecognized conversion specifier [d] starting at position 16 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [thread]
ERROR StatusLogger Unrecognized conversion specifier [thread] starting at position 25 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [level]
ERROR StatusLogger Unrecognized conversion specifier [level] starting at position 35 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [logger]
ERROR StatusLogger Unrecognized conversion specifier [logger] starting at position 47 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [msg]
ERROR StatusLogger Unrecognized conversion specifier [msg] starting at position 54 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [n]
ERROR StatusLogger Unrecognized conversion specifier [n] starting at position 56 in conversion pattern.
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'log4j2.debug' to show Log4j2 internal initialization logging.
ERROR StatusLogger Unrecognized format specifier [d]
ERROR StatusLogger Unrecognized conversion specifier [d] starting at position 16 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [thread]
ERROR StatusLogger Unrecognized conversion specifier [thread] starting at position 25 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [level]
ERROR StatusLogger Unrecognized conversion specifier [level] starting at position 35 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [logger]
ERROR StatusLogger Unrecognized conversion specifier [logger] starting at position 47 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [msg]
ERROR StatusLogger Unrecognized conversion specifier [msg] starting at position 54 in conversion pattern.
ERROR StatusLogger Unrecognized format specifier [n]
ERROR StatusLogger Unrecognized conversion specifier [n] starting at position 56 in conversion pattern.

When I start the application JAR with the -Dlog4j2.debug option I see a lot of messages, and some seem to say, that the configuration cannot be loaded (which is still at the same place). 当我使用-Dlog4j2.debug选项启动应用程序JAR时,我看到很多消息,并且似乎有些消息说无法加载配置(仍然位于同一位置)。 Here an excerpt: 这里摘录:

DEBUG StatusLogger Using configurationFactory org.apache.logging.log4j.core.config.ConfigurationFactory$Factory@2a33fae0
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'log4j2.debug' to show Log4j2 internal initialization logging.

I even used the -Dlog4j.configurationFile option, pointing directly to the XML in the file system, but the result stays the same. 我什至使用了-Dlog4j.configurationFile选项,直接指向文件系统中的XML,但是结果保持不变。

Again, starting the application from the IDE and not via java -jar ... works fine. 同样,从IDE而不是通过java -jar ...启动应用程序也可以。 It seems to me as if the spring-rabbitmq dependency brings some extra log4j stuff that interferes with my configuration. 在我看来, spring-rabbitmq依赖项带来了一些额外的log4j东西,这些东西会干扰我的配置。 I'm totally fishing in murky waters. 我完全在浑浊的水域钓鱼。

So, after a lot of research I can answer my question with the following. 因此,经过大量研究,我可以通过以下方式回答我的问题。

It is not enough to simply add the Spring-Rabbit-MQ org.springframework.amqp:spring-rabbit dependency to let the Log4J2 configuration fail. 这是不够的,只是加春兔MQ org.springframework.amqp:spring-rabbit的依赖,让Log4J2配置失败。 It's the combination with another dependency, that is not listed in my example: com.fasterxml.jackson.core:jackson-databind . 它是与另一个依赖关系的组合,在我的示例中未列出: com.fasterxml.jackson.core:jackson-databind

To sum it up. 把它们加起来。 This does not work: 这不起作用:

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.3'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
compile group: 'com.lmax', name: 'disruptor', version: '3.3.7'
compile group: 'org.springframework.amqp', name: 'spring-rabbit', version: '2.0.2.RELEASE'

But this works (without Spring): 但这有效(没有Spring):

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.3'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
compile group: 'com.lmax', name: 'disruptor', version: '3.3.7'

And this works (without Jackson): 这有效(没有杰克逊):

compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
compile group: 'com.lmax', name: 'disruptor', version: '3.3.7'
compile group: 'org.springframework.amqp', name: 'spring-rabbit', version: '2.0.2.RELEASE'

So the combination of Jackson and Spring breaks Log4J2. 因此,Jackson和Spring的结合打破了Log4J2。 Interestingly, without Jackson, my program works as well, even if Jackson is under heavy use. 有趣的是,即使没有大量使用Jackson,我的程序也能正常运行。 Let's have a look on that, what gradle dependecies has to say: 让我们来看看, gradle dependecies所要说的是:

compile - Dependencies for source set 'main' (deprecated, use 'implementation ' instead).
+--- org.apache.logging.log4j:log4j-api:2.10.0
+--- org.apache.logging.log4j:log4j-core:2.10.0
|    \--- org.apache.logging.log4j:log4j-api:2.10.0
+--- com.lmax:disruptor:3.3.7
\--- org.springframework.amqp:spring-rabbit:2.0.2.RELEASE
     +--- org.springframework.amqp:spring-amqp:2.0.2.RELEASE
     |    \--- org.springframework:spring-core:5.0.3.RELEASE
     |         \--- org.springframework:spring-jcl:5.0.3.RELEASE
     +--- com.rabbitmq:amqp-client:5.1.2
     |    \--- org.slf4j:slf4j-api:1.7.25 -> 1.8.0-alpha2
     +--- com.rabbitmq:http-client:1.3.1.RELEASE
     |    +--- org.apache.httpcomponents:httpclient:4.5.3
     |    |    +--- org.apache.httpcomponents:httpcore:4.4.6
     |    |    +--- commons-logging:commons-logging:1.2
     |    |    \--- commons-codec:commons-codec:1.9 -> 1.11
     |    \--- com.fasterxml.jackson.core:jackson-databind:2.9.2
     |         +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
     |         \--- com.fasterxml.jackson.core:jackson-core:2.9.2
     +--- org.springframework:spring-context:5.0.3.RELEASE
     |    +--- org.springframework:spring-aop:5.0.3.RELEASE
     |    |    +--- org.springframework:spring-beans:5.0.3.RELEASE
     |    |    |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     |    |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    +--- org.springframework:spring-core:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-expression:5.0.3.RELEASE
     |         \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     +--- org.springframework:spring-messaging:5.0.3.RELEASE
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     +--- org.springframework:spring-tx:5.0.3.RELEASE
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     +--- org.springframework:spring-web:5.0.3.RELEASE
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     \--- org.springframework.retry:spring-retry:1.2.1.RELEASE
          \--- org.springframework:spring-core:4.3.9.RELEASE -> 5.0.3.RELEASE (*)

Oh, wait, there's also a Jackson within the Spring AMQP. 哦,等等,春季AMQP中还有一个杰克逊。 Well, that solves the riddle, why I can still use Jackson after removing the dependency. 好了,这解决了一个难题,为什么在删除依赖项后仍然可以使用Jackson。 But this is very intransparent to me and depends on the Spring AMQP package to deliver a core dependency for me. 但这对我来说是非常不透明的,它依赖于Spring AMQP软件包为我提供核心依赖。 So what I finally did is this, and it seems to work: 所以我最后要做的是,它似乎起作用了:

compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.3'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
compile group: 'com.lmax', name: 'disruptor', version: '3.3.7' version: '2.12.0'
compile (group: 'org.springframework.amqp', name: 'spring-rabbit', version: '2.0.2.RELEASE') {
    exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
}

The dependency tree looks like the following now: 依赖关系树现在如下所示:

compile - Dependencies for source set 'main' (deprecated, use 'implementation ' instead).
+--- com.fasterxml.jackson.core:jackson-databind:2.9.3
|    +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0
|    \--- com.fasterxml.jackson.core:jackson-core:2.9.3
+--- org.apache.logging.log4j:log4j-api:2.10.0
+--- org.apache.logging.log4j:log4j-core:2.10.0
|    \--- org.apache.logging.log4j:log4j-api:2.10.0
+--- com.lmax:disruptor:3.3.7
\--- org.springframework.amqp:spring-rabbit:2.0.2.RELEASE
     +--- org.springframework.amqp:spring-amqp:2.0.2.RELEASE
     |    \--- org.springframework:spring-core:5.0.3.RELEASE
     |         \--- org.springframework:spring-jcl:5.0.3.RELEASE
     +--- com.rabbitmq:amqp-client:5.1.2
     |    \--- org.slf4j:slf4j-api:1.7.25 -> 1.8.0-alpha2
     +--- com.rabbitmq:http-client:1.3.1.RELEASE
     |    \--- org.apache.httpcomponents:httpclient:4.5.3
     |         +--- org.apache.httpcomponents:httpcore:4.4.6
     |         +--- commons-logging:commons-logging:1.2
     |         \--- commons-codec:commons-codec:1.9 -> 1.11
     +--- org.springframework:spring-context:5.0.3.RELEASE
     |    +--- org.springframework:spring-aop:5.0.3.RELEASE
     |    |    +--- org.springframework:spring-beans:5.0.3.RELEASE
     |    |    |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     |    |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    +--- org.springframework:spring-core:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-expression:5.0.3.RELEASE
     |         \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     +--- org.springframework:spring-messaging:5.0.3.RELEASE
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     +--- org.springframework:spring-tx:5.0.3.RELEASE
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     +--- org.springframework:spring-web:5.0.3.RELEASE
     |    +--- org.springframework:spring-beans:5.0.3.RELEASE (*)
     |    \--- org.springframework:spring-core:5.0.3.RELEASE (*)
     \--- org.springframework.retry:spring-retry:1.2.1.RELEASE
          \--- org.springframework:spring-core:4.3.9.RELEASE -> 5.0.3.RELEASE (*)

I must admit that I not fully understand why the combination of two Jackson dependencies brings the Log4J2 configuration down, but now it works with this strategy: 我必须承认,我不完全理解为什么两个Jackson依赖项的组合会使Log4J2配置下降,但是现在它可以使用以下策略:

  • Declare Jackson dependency explicitly (make transparent, that the application uses Jackson) 显式声明Jackson依赖项(使应用程序使用Jackson透明化)
  • Exclude Jackson from Spring dependency 将Jackson排除在Spring依赖之外

And what I really don't get: Why do all combinations work from within the IDE, but later fail when running the JAR? 我真正不明白的是:为什么所有组合都可以在IDE中运行,但是后来在运行JAR时失败了?

This is a known issue with log4j, reported over 3 years ago. 这是3年前报告的log4j的已知问题 It comes up when you use the shadowjar plugin. 当您使用shadowjar插件时,它就会出现。 See shadowjar issue here . 在这里查看shadowjar问题。

You can read both tickets to get a better understanding, but if you're looking for a point-and-click solution, just use this gradle plugin: 您可以阅读两张票证,以更好地理解它们,但是,如果您正在寻找一种点击解决方案,只需使用 gradle插件即可:

plugins {
  id "com.github.johnrengelman.shadow" version "2.0.2"
  id "de.sebastianboegl.shadow.transformer.log4j" version "2.2.0"
}

... or revert to log4j 2.0.2. ...或恢复为log4j 2.0.2。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM