Ist log4j2 mit Java 11 kompatibel?

Lesezeit: 9 Minuten

Benutzer-Avatar
Dmitrij Dumanskij

Ich habe versucht, mein Projekt auf dem neuesten Java 11 auszuführen. Alles funktioniert, außer dem spezifischen Dateilogger. Die Protokollierung funktioniert gut auf früheren Java-Versionen – 10, 9, 8, aber nicht auf Java 11.

Während des Serverlaufs sehe ich nur 1 Warnung:

WARNUNG: sun.reflect.Reflection.getCallerClass wird nicht unterstützt. Dies wirkt sich auf die Leistung aus.

Hier meine Konfiguration:

<Configuration>

    <Appenders>

        <RollingFile name="postgresDBLog" fileName="${sys:logs.folder}/postgres.log"
              filePattern="${sys:logs.folder}/archive/postgres.log.%d{yyyy-MM-dd}">
            <PatternLayout>
                <pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>

        <RollingFile name="workersLog" fileName="${sys:logs.folder}/worker.log"
                     filePattern="${sys:logs.folder}/archive/worker.log.%d{yyyy-MM-dd}">
            <PatternLayout>
                <pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>

        <RollingFile name="statsLog" fileName="${sys:logs.folder}/stats.log"
                     filePattern="${sys:logs.folder}/archive/stats.log.%d{yyyy-MM-dd}">
            <PatternLayout>
                <pattern>%msg%n</pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>

        <RollingFile name="userLog" fileName="${sys:logs.folder}/blynk.log"
                     filePattern="${sys:logs.folder}/archive/blynk.log.%d{yyyy-MM-dd}">
            <PatternLayout>
                <pattern>%d{HH:mm:ss.SSS} %-5level- %msg%n</pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
        </RollingFile>

    </Appenders>

    <Loggers>

        <Logger name="cc.blynk.server.workers" level="debug" additivity="false">
            <appender-ref ref="workersLog"/>
        </Logger>
        <Logger name="cc.blynk.server.workers.StatsWorker" level="debug" additivity="false">
            <appender-ref ref="statsLog"/>
        </Logger>
        <Logger name="cc.blynk.server.db" level="debug" additivity="false">
            <appender-ref ref="postgresDBLog"/>
        </Logger>
        <Logger name="com.zaxxer.hikari" level="OFF" additivity="false">
        </Logger>

        <Logger name="org.asynchttpclient.netty.channel" level="OFF" additivity="false" />

        <!-- turn off netty errors in debug mode for native library loading
         https://github.com/blynkkk/blynk-server/issues/751 -->
        <Logger name="io.netty" level="INFO" additivity="false" />

        <Root>
            <AppenderRef ref="userLog"/>
        </Root>

    </Loggers>
</Configuration>

Alle Logger, außer userLog funktioniert gut. Jedoch, userLog ist leer.

log4j2 version 2.11.1

Ubuntu 16.04.5 LTS

java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)

Aktualisieren:

Hinzufügen level="info" auf die Root-Ebene behebt das Problem.

    <Root level="info">
        <AppenderRef ref="userLog"/>
    </Root>

In meinem Projekt habe ich jedoch einen Code verwendet, der eine Protokollebene basierend auf der Eigenschaftendatei festgelegt hat. Hier ist ein Code:

private static void changeLogLevel(String level) {
    Level newLevel = Level.valueOf(level);
    LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    Configuration conf = ctx.getConfiguration();
    conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(newLevel);
    ctx.updateLoggers(conf);
}

Scheint, als ob dieser Teil mit Java 11 nicht mehr funktioniert.

  • Irgendetwas, das Sie beim Wechsel von Java10 zu Java11 beobachtet haben? Sieht seltsam aus.

    – Namann

    29. Oktober 2018 um 15:59 Uhr


  • Ich habe nichts geändert, gleiches Glas, gleiche Umgebung, verschiedene JVMs.

    – Dmitrij Dumanskij

    29. Oktober 2018 um 16:00 Uhr


  • @nullpointer Ich kann dieselbe Warnung sehen, wenn ich meine App auf JDK 11 (mit 2.11.1 und 2.11.0) ausführe. Es gibt keine Warnung zu JDK 10. Mein Projekt ist groß, daher ist es schwierig, ein reproduzierbares Beispiel zu erstellen.

    – MartyIX

    2. November 2018 um 9:01 Uhr

  • “Scheint so, als würde dieser Teil mit Java 11 nicht mehr funktionieren.” – Die Warnung sagt nicht, dass es nicht funktioniert. Es sagt, es funktioniert … langsam.

    – Stefan C

    31. Januar 2019 um 0:20 Uhr

  • Ja, aber dieser Code funktioniert nicht mehr mit Java 11.

    – Dmitrij Dumanskij

    31. Januar 2019 um 8:29 Uhr

Wenn jemand Maven verwendet und das gleiche Problem beim Zusammenbau eines flachen Glases hat, habe ich Folgendes getan, um das gleiche Problem zu beheben:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>foo.bar.Generate</mainClass>
                        <manifestEntries>
                            <Multi-Release>true</Multi-Release>
                        </manifestEntries>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

Der wichtige Teil ist <Multi-Release>true</Multi-Release>.

Beachten Sie, dass der Java-Code, den ich jetzt verwende, um das Logger-Level zu ändern, folgender ist:

Configurator.setAllLevels("foo.bar", Level.DEBUG);

  • Diese feste Mine. Ich habe <Root level="DEBUG"> in meinem log4j2.xml.

    – Silber

    6. November 2019 um 12:37 Uhr

  • Funktioniert bei mir auch. Mit Gradle habe ich hinzugefügt "Multi-Release": true zu jar { manifest.attributes.

    – petarow

    24. Januar 2020 um 12:41 Uhr

  • Dies hat mein Protokollierungsproblem behoben, aber eine Vielzahl anderer Probleme mit Jackson in AWS Version 1-Jars verursacht. Nachdem ich mehrere Stunden versucht hatte, das Problem zu beheben, musste ich es zurücksetzen.

    – markthegrea

    27. April 2020 um 15:42 Uhr

  • für gradle habe ich dieses jar { manifest { attributes ( “Manifest-Version”: “1.0”, “Multi-Release”: true ) } from { configurations.compileClasspath.collect { it.isDirectory() ? es : zipTree(it) } } }

    – KS KianSeng

    12. März 2021 um 7:26 Uhr

  • Aber können Sie den Grund erklären (warum diese Syntax behoben werden kann und das Warnleistungsproblem verschwindet?)

    – Lei Yang

    26. Januar um 15:49 Uhr

Log4J2 ist natürlich kompatibel es verwendet die JDK Multi-Release-Funktion oder hinein Mehr Details.

ABER…

1) Erstens, wenn Sie – wie ich – die slf4j-Schnittstelle verwenden, müssen Sie ein anderes Maven-Artefakt verwenden, siehe http://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html

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

die alle Abhängigkeiten als ‘mvndependency:tree’ hinzufügt, zeigt:

\- org.apache.logging.log4j:log4j-slf4j18-impl:jar:2.12.1:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.8.0-alpha2:compile
[INFO] +- org.apache.logging.log4j:log4j-api:jar:2.12.1:compile
[INFO] \- org.apache.logging.log4j:log4j-core:jar:2.12.1:runtime

2) Und zweitens, wenn Sie – wie ich – ein einziges JAR erstellen, das alle Abhängigkeiten enthält, müssen Sie auch den Multi-Release-Manifesteintrag hinzufügen, siehe https://issues.apache.org/jira/browse/LOG4J2-2537
oder in meinem Projekt pom.xml und suchen

<Multi-Release>true</Multi-Release>

  • Dies ist die richtige Antwort für Java 11. log4j überrascht mich immer wieder.

    – Wirbel

    19. Juni 2021 um 5:18 Uhr

Wenn Sie diese Meldung erhalten, ist Ihre Anwendung nicht für die Verwendung von Multi-Release-Jars eingerichtet. Log4j unterstützt Java 9+ durch die Verwendung von Stackwalker in einer Version von StackLocator, die sich in META-INF/versions/9 befindet. Je nachdem, wie Ihre Anwendung funktioniert, müssen Sie möglicherweise Multi-Release im JAR-Manifest auf „true“ setzen. Dies gilt für Spring Boot-Gläser. Ohne Multi-Release-Unterstützung verwenden Sie die Pre-Java 9-Version von StackLocator, die versucht, Reflection.getCallerClass() zu verwenden. Diese Klasse wurde in Java 9 entfernt. Log4j wird auf eine langsamere Methode zur Berechnung von Stack-Positionen zurückgreifen, aber es wird immer noch funktionieren. Daher die Warnung.

  • Vielen Dank. Das Multi-Release-Jar ist jedoch kein Muss. Ich brauche es nicht, also packe ich es nicht als Multi-Release. Warum kann log4j2 einfach nicht prüfen, ob die erforderliche Klasse verfügbar ist, und fortfahren, wenn dies der Fall ist? Was bringt es, sich auf das Manifest zu verlassen? Das könnte falsch konfiguriert oder irreführend sein. Scheint mir ein log4j2-Fehler zu sein.

    – Dmitrij Dumanskij

    31. Januar 2019 um 8:32 Uhr


  • Du hast recht, dass es kein Muss ist. Wenn es Ihnen egal ist, dass die Leistung Ihrer Anwendung beeinträchtigt wird, und Sie mit der Warnung leben können, gibt es kein Problem. Der Punkt, sich auf das Manifest zu verlassen, ist die Standardmethode, mit der Bibliotheken mehrere Java-Versionen ab Java 9 unterstützen sollen. Wenn Ihnen die Funktionsweise nicht gefällt, fürchte ich, müssen Sie dies mit den OpenJDK-Leuten besprechen. Die Verwendung anderer Methoden zur Bestimmung der korrekten zu verwendenden Implementierung hätte andere Probleme verursacht, da Klassen, die für mehrere Java-Versionen im Klassenpfad erstellt wurden, dazu führen können, dass Tools fehlschlagen.

    – rgoers

    31. Januar 2019 um 15:02 Uhr

  • Es tut uns leid. Ich verstehe das Problem immer noch nicht. Es gibt System.getProperty(“java.version”), das von log4j2 zur Laufzeit verwendet werden könnte. Liege ich falsch?

    – Dmitrij Dumanskij

    31. Januar 2019 um 15:17 Uhr


  • Ja, du liegst falsch. Die StackWalker-API kann nur mit einem Java 9+-Compiler kompiliert werden und hat eine Klassenversionsnummer für Java 9. Der Rest von Log4j ist für Java 7 kompiliert. Wenn sich eine Java 9-Klasse neben Klassen befindet, die auf Java 7 ausgerichtet sind, werden viele Tools dies tun scheitern, wenn sie auf die Klasse treffen. Sie werden nicht fehlschlagen, wenn sie in den Multi-Release-Speicherort gepackt werden, da dieser vor Java 9 ungültig war. Das Problem hat also nichts damit zu tun, nur eine Version erkennen zu können.

    – rgoers

    31. Januar 2019 um 15:22 Uhr


  • Aha, log4j2 ist also als Multijar gepackt … Das sind schlechte Nachrichten. Vielleicht war es besser und einfacher, nur unterschiedliche Builds für Java7+ und für Java9+ bereitzustellen. Nur Gedanken.

    – Dmitrij Dumanskij

    31. Januar 2019 um 15:49 Uhr

Scheint, als ob dieser Teil mit Java 11 nicht mehr funktioniert.

Ich bin auf dasselbe Problem gestoßen, als ich die LogLevel-Einstellungen mithilfe von LoggerContext programmgesteuert aktualisierte, nachdem ich von JDK 8 auf JDK 11 aktualisiert hatte LogManager.getContext(boolean) kann den LoggerContext nicht finden, den er erstellt, und gibt eine neue Instanz zurück – das Ändern dieses neuen Objekts hat keine Auswirkung. Die Angabe des Classloaders der LogManager-Klasse von Log4j hat das Problem in unserem Fall behoben:

LoggerContext ctx = (LoggerContext) LogManager.getContext(LogManager.class.getClassLoader(), false);

Diese Nachricht kommt von org/apache/logging/log4j/util/StackLocator.<classconstructor> was Teil davon ist log4j2-api.jar (oder log4j-api-2.x.y.jar etc).

Sie erhalten diese Nachricht, weil einige kluge Köpfe entschieden haben sun.reflect.Reflection.getCallerClass muss aus JRE entfernt werden (schätze, sie haben eine Seite aus Herostratus ‘Buch oder so etwas gezogen). Dies ist tatsächlich in Openjdk11 passiert.

Wohlgemerkt, Sie sollten diese Meldung nicht erhalten, wenn Sie eine nicht zu alte Version von haben log4j2-api.jarwie es ist ein Multi-Release-Jar was bedeutet, dass es eine andere Implementierung dieser Klasse für Java9+ enthält (META-INF/versions/9/org/apache/logging/log4j/util/StackLocator.class), die diese Meldung nicht ausgibt.

Wenn Sie jedoch ein Helping Product(TM) wie Spring Boot verwenden, das über einen eigenen Classloader verfügt, ist es möglicherweise nicht mit Multi-Release-JAR-kompatibel, sodass es das Java8-kompatible lädt StackLocator.class anstelle von Java9+ kompatibel, und Sie erhalten immer noch diese Meldung.

1152300cookie-checkIst log4j2 mit Java 11 kompatibel?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy