log4j zweimal protokollieren


70

Ich verwende log4j, um Fehler und andere Systeminformationen zu protokollieren. Aber kommen Sie von den Informationen, die zweimal auf INFO-Ebene protokolliert wurden.

public static void main(final String... args) throws Exception {

    LOGGER.info("program started");
    try {
        // try body codes
    } catch (Exception ex) {
        LOGGER.info("program start-up failed.",ex);
    }
}

Wenn das Programm jedoch die zweimal protokollierten Informationen startet oder fehlschlägt, kann mir jeder helfen, den Grund dafür zu finden.


Möglicherweise liegt ein Konfigurationsproblem oder ein Initialisierungsproblem vor. Wo initialisieren Sie den Logger? Rufen Sie Logger.getLogger (SomeClass.class) nicht zweimal auf? Ein zusätzlicher Code könnte uns weitere Informationen geben, um Ihnen zu helfen.
MaSEL

Antworten:


98

Es sieht so aus, als würden Ihre Nachrichten einmal vom Root-Logger und erneut vom jeweiligen Logger protokolliert, da möglicherweise beide Appender konfiguriert sind (möglicherweise an verschiedenen Stellen - in einer Eigenschaftendatei und dann im Code).

Dies kann behoben werden, indem Sie die Additivität in Ihrem Logger auf false setzen. Das Log4j- Handbuch erwähnt die Additivität im Abschnitt Anhänge und Layout. Überprüfen Sie dies


4
Sollten Sie das so lösen oder ein Pflaster, das ein größeres Konfigurationsproblem maskiert?
Daniel Kaplan

1
Ohne den Logger wird nichts protokolliert. Wenn ich den Logger wieder hinzufüge, wird er zweimal protokolliert. Wenn ich die Additivität auf false setze, wird sie einmal protokolliert. Was ist hier los?
James Watkins

@DanielKaplan Wenn Ihre Logger eine hierarchische Struktur haben, ja. Angenommen, Sie möchten nur FEHLER-Nachrichten für alle Klassen mit Ausnahme von Foo, von dem Sie alle Nachrichten sehen möchten. Sie haben die Additivität des Foo-Loggers auf false gesetzt, damit ERROR-Meldungen nicht bis zum Stammverzeichnis fortgesetzt und erneut gedruckt werden. Ohne Additivität wäre die Konfiguration viel komplizierter und weniger wartbar, daher würde ich sagen, dass dies korrekt ist.
user812786

1
Ich denke, es wäre gut, das Beispiel der XML-Konfiguration in diese Antwort aufzunehmen, damit man den Additivitätsparameter schnell hinzufügen kann, ohne auf das Handbuch zu verweisen.
Linie

@DanielKaplan Ja, zuerst dachte ich wie Sie und mochte das Additivitäts-Pflaster nicht, bis ich auf der Konfigurationsseite den Hinweis "Log4j stellt eine Standardkonfiguration bereit, wenn es keine Konfigurationsdatei finden kann" und die Standardkonfigurationskraft sah Ein Root-Logger, auch wenn Sie keinen Root-Logger konfiguriert haben und der Root-Logger die zweite Kopie des Protokolls protokolliert. Aus diesem Grund haben die Ersteller von die Additivitätskonfiguration erfunden und empfehlen, sie zu verwenden. Jetzt fühle ich mich besser, die Additivitätsfunktion zu verwenden. log4j
Buchhalter م

35

Stimmen Sie mit atlantis überein.

log4j.rootCategory=INFO, console
log4j.logger.org.hibernate=INFO

Die obigen Eigenschafteneinstellungen führen zu einer doppelten Protokollierung.

Jedoch hinzufügen

log4j.additivity.org.hibernate=false

Das Problem wurde behoben.

Lesen Sie Seite 62 dieses Buches. http://books.google.com/books?id=hZBimlxiyAcC&printsec=frontcover#v=onepage&q&f=false


6
sollte das nicht "falsch" sein, nicht "wahr"?
James Scriven

Google-Bücher scheinen bestimmte Seiten zufällig auszublenden. Hier ist ein Blog-Beitrag, den ich hilfreich fand. Es enthält ein ausführlicheres Beispiel darunter auch einige log4j.category ... Einträge
Glenn Lawrence

31

Für diejenigen, die das XML-Format verwenden:

<logger name="package.class" additivity="false">
    <level value="info" />
    <appender-ref ref="file" />
    <appender-ref ref="console" />
</logger>

Hinweis: Standardmäßig ist für Logger das Additivitätsflag auf true gesetzt.


6

Einfach hinzufügen

logger.setadditivity(false);

zu Ihrem Code ( Referenz ).

Wir haben doppelte Ergebnisse in der Konsole, weil Appender keine Singletons sind, sondern additiv. Das heißt, eine Kategorie erbt alle Appender von ihren Vorfahren (standardmäßig). Wenn wir einer Kategorie einen Appender hinzufügen und dieser in denselben zugrunde liegenden Stream (Konsole, dieselbe Datei usw.) wie ein anderer Appender schreibt, wird dieselbe Protokollmeldung zweimal (oder öfter) im Protokoll angezeigt. Wenn zwei Kategorien in einer Hierarchie so konfiguriert sind, dass sie denselben Appendernamen verwenden, schreibt Log4j außerdem zweimal in diesen Appender. Für diese Kategorie konfiguriert


1
" Referenz " ist jetzt ein toter Link. Der Logger von log4j 2.x hat keine setAdditivity()mehr.
Gerold Broser

2

Wenn Sie das Programm mit einem Java-Debugger ausführen können, setzen Sie einen Haltepunkt in das Programm, an dem einer dieser doppelten Protokollierungsaufrufe auftritt.

Untersuchen Sie das Logger-Objekt im Debugger. Wenn es sich um einen org.apache.log4j.Logger (v 1.2.x) handelt, verfügt er möglicherweise über einen AppenderAttachableImpl. Sie können AppenderAttachableImpl nach der Appender-Liste abfragen.

Wenn Sie mehr als einen Appender finden, könnte dies das Problem sein - und ein Hinweis darauf, es zu beheben.


1

Ich hatte das gleiche Problem und wurde behoben, indem alle Appender aus dem Root-Logger entfernt wurden. Ich weiß nicht warum, aber ich löse mein Problem und teile:

        // Root
    rootLogger = Logger.getRootLogger();
    rootLogger.removeAllAppenders(); // Solve my problem
        // CSV
    csvLogger = rootLogger.getLogger("csvLogger");
        // Txt
    txtLogger = rootLogger.getLogger("txtLogger");

Ohne diese zusätzliche Zeile wird die Additivität sogar auf false gesetzt, wenn ich mich mit meinem csvLogger oder txtLogger anmelde, wird zweimal protokolliert.


0

Eine mögliche Alternative zum Anpassen der additivityEigenschaft besteht darin, Ihre Logger von den spezifischsten bis zu den allgemeinsten zu untersuchen. Im folgenden Beispiel wird eine doppelte Protokollierung in der Konsole für alle in foo.bar.LoggingExampleClass auftretenden Protokollereignisse erwartet. Es ist sicher, den zusätzlichen Konsolen-Appender aus dem foo.bar.LoggingExampleClass-Logger zu entfernen, da er bereits vom Root-Logger abgedeckt wird.

<Logger name="foo.bar.LoggingExampleClass" level="DEBUG">
  <AppenderRef ref="Console" />   <!-- THIS APPENDER COULD BE REMOVED -->
  <AppenderRef ref="FooBarPackageLogging" />
</Logger>

<Root level="WARN">
  <AppenderRef ref="Console" />
  <AppenderRef ref="MainLogFile" />
</Root>

Es gibt Kompromisse sowohl beim Additivitätsanpassungsansatz als auch beim Appenderanpassungsansatz. Durch Deaktivieren der Additivität wird möglicherweise versehentlich verhindert, dass der Appender eines gewünschten generischen Loggers verwendet wird. Im obigen Beispiel würde das Festlegen der additivity="false"Eigenschaft im foo.bar.LoggingExampleClass-Logger bedeuten, dass das Protokollierungsereignis nicht an die MainLogFile angehängt wird, auf die im Root-Logger verwiesen wird.

Andererseits kann es problematisch sein, sich auf übergeordnete Appender zu verlassen, wenn die übergeordneten Appender geändert werden, ohne die Auswirkungen auf detailliertere Logger zu untersuchen. Angenommen, die Protokollierungsereignisse foo.bar.LoggingExampleClass müssen in die Konsole geschrieben werden. Sie befinden sich derzeit aufgrund der Additivität in der obigen Beispielkonfiguration, auch wenn der Konsolen-Appender von foo.bar.LoggingExampleClass Logger entfernt wurde. Wenn der Konsolen-Appender jedoch auch ohne zusätzliche Anpassungen aus dem Root-Logger entfernt würde, wäre die Anforderung nicht mehr erfüllt.


0

Dies ist eine weitere Option, wenn Sie die Funktion "Additivität" nicht verwenden möchten.

In meinem Fall (und meistens auch in Ihrem Fall) befindet sich der Root-Logger hinter diesem zusätzlichen Protokoll, und Sie haben einen anderen höheren Logger in Ihren Konfigurationen, so etwas

  <Loggers>
    <Logger name="com.foo.Bar" level="trace">
      <AppenderRef ref="Console"/>
    </Logger>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>

Dies führt zu doppelten Protokollen. Wenn Sie den Root-Logger überhaupt aus dieser Konfigurationsdatei entfernt haben, log4jwird der Standard-Root-Logger erzwungen. Überprüfen Sie diesen Hinweis

Log4j stellt eine Standardkonfiguration bereit, wenn keine Konfigurationsdatei gefunden werden kann. Die in der DefaultConfiguration-Klasse bereitgestellte Standardkonfiguration wird eingerichtet:

Ein ConsoleAppender, der an den Root-Logger angehängt ist .

Ein PatternLayout, das auf das an den ConsoleAppender angehängte Muster "% d {HH: mm: ss.SSS} [% t]% -5level% logger {36} -% msg% n" festgelegt ist

Beachten Sie, dass Log4j den Root-Logger standardmäßig Level.ERROR zuweist.

Wenn Sie den Standard-Root-Logger überschreiben und erzwingen möchten, dass er nicht protokolliert wird , können Sie den Appender wie folgt aus Ihrer Konfigurationsdatei entfernen

<Root level="error">
</Root>

Dies ist nur eine weitere Option. Ich verwende jedoch gerne die empfohlene Methode und setze das Attribut "Additivität" auf den untergeordneten Logger

<Logger name="com.foo.Bar" level="trace" additivity="false">
  <AppenderRef ref="Console"/>
</Logger>

-1

In deiner resources/log4.properties Datei.

Wenn Sie in dieser Konfigurationsdatei " log4j.rootLogger= DEBUG, file" haben, schließen Sie " log4j.logger.org.springframework=DEBUG, file" nicht ein. Behalten Sie einfach den log4j.rootLogger-Teil.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.