Warum erklären wir Logger als statisch endgültig?

131

Warum ist es in Java empfehlenswert, einen Logger zu deklarieren static final?

private static final Logger S_LOGGER
user489041
quelle

Antworten:

209
  • private- damit keine andere Klasse Ihren Logger entführen kann
  • static - Es gibt also nur eine Logger-Instanz pro Klasse, wodurch auch Versuche vermieden werden, Logger zu serialisieren
  • final - Der Logger muss während der gesamten Lebensdauer der Klasse nicht geändert werden

Außerdem bevorzuge ich, dass der Name logso einfach wie möglich und dennoch beschreibend ist.

EDIT: Es gibt jedoch eine interessante Ausnahme zu diesen Regeln:

protected final Logger log = LoggerFactory.getLogger(getClass());

im Gegensatz zu:

private static final Logger log = LoggerFactory.getLogger(Foo.class);

Auf die erstere Weise können Sie in allen Klassen der Vererbungshierarchie denselben Loggernamen (Namen der tatsächlichen Klasse) verwenden. Wenn also Barverlängert Foo, werden beide beim BarLogger protokolliert . Einige finden es intuitiver.

Tomasz Nurkiewicz
quelle
35
wenn statisch und endgültig, dann eher LOG (Großbuchstaben)
zacheusz
39
@zacheusz , ich weiß, das ist der Punkt. Einige folgen religiös der Java-Namenskonvention (daran ist nichts auszusetzen), aber ich bevorzuge es, einfacher zu schreiben und den logNamen angenehmer zu lesen, als den Code mit zu streuen LOG. Nur eine Frage der Entwicklung. Teamvereinbarung.
Tomasz Nurkiewicz
27
Bitte beachten Sie, dass es nicht mehr immer empfohlen wird, Logger als statisch und endgültig zu deklarieren (siehe Abschnitt slf4j.org/faq.html#declared_static und wiki.apache.org/commons/Logging/FrequentlyAskedQuestions). Soll ich Logreferenzen als statisch deklarieren oder nicht?
Matthew Farwell
6
@zacheusz Der Großbuchstabe wird für Konstanten verwendet. Logger ist nicht konstant. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman
2
@zacheusz nicht alle statischen endgültigen Attribute sollten GROSSBUCHSTABEN sein: stackoverflow.com/questions/1417190/…
bsmk
15

Überprüfen Sie diesen Blog-Beitrag: Befreien Sie sich von Java Static Loggers . So verwenden Sie slf4j mit jcabi-log :

import com.jcabi.log.Logger;
class Foo {
  void save(File f) {
    Logger.info(this, "file %s saved successfully", f);
  }
}

Und verwenden Sie dieses statische Rauschen nie mehr.

yegor256
quelle
Eine interessante Alternative und definitiv sauberer. Ich frage mich, wie sich dies im Vergleich zu einzelnen Klassenloggern skaliert.
Ross
12
Schreiben Sie jedes Mal einen längeren Logger .. (dies, ...). Nein, nein.
Mikhail Boyarsky
Der erste Kommentar im zugehörigen Blog-Beitrag weist auf die böse Seite der statischen Methoden hin :) Die Verwendung von Private Final Logger ist also die beste Vorgehensweise, denke ich.
Bahadir Tasdemir
5

staticbedeutet, dass Sie nur einen Logger pro Klasse erstellen, nicht einen Logger pro Instanz Ihrer Klasse. Im Allgemeinen ist dies das, was Sie möchten - da die Logger in der Regel nur je nach Klasse variieren.

finalbedeutet, dass Sie den Wert der loggerVariablen nicht ändern werden. Dies ist der Fall, da Sie fast immer alle Protokollnachrichten (von einer Klasse) an denselben Protokollierer senden. Selbst in den seltenen Fällen, in denen eine Klasse einige Nachrichten an einen anderen Logger senden möchte, ist es viel klarer, eine andere Logger-Variable (z. B. widgetDetailLogger) zu erstellen, als den Wert einer statischen Variablen im laufenden Betrieb zu ändern.

Andrzej Doyle
quelle
4

Wann möchten Sie den Wert des Feldes ändern?

Wenn Sie den Wert niemals ändern, wird durch das Festlegen des Felds deutlich, dass Sie den Wert niemals ändern werden.

Jon Skeet
quelle
1
In vielen Fällen ist es offensichtlich, ohne das Wort final hinzuzufügen, was in diesem Fall zu einer Art Müll wird.
Dima
2
@Dima: Nun , ich bin immer noch dankbar , dass der Compiler noch einen Fehler aus , wenn ich Sie versehentlich versuchen , den Wert in diesen Fällen zu ändern ...
Jon Skeet
3

Normalerweise initialisieren Sie den Logger so, dass er unter Verwendung des Klassennamens protokolliert wird. Wenn diese nicht statisch wären, würde jede Instanz der Klasse eine Instanz davon haben (hoher Speicherbedarf), aber alle diese Logger würden dies tun teilen die gleiche Konfiguration und verhalten sich genauso. Das ist der Grund für das staticbisschen. Da LoggerKonflikte jeweils mit dem Klassennamen initialisiert werden, deklarieren Sie privatesie , um Konflikte mit Unterklassen zu vermeiden, damit sie nicht vererbt werden können. Das finalkommt von dem Punkt, an dem Sie das normalerweise Loggerwährend der Ausführung nicht ändern - also haben Sie es nach der Initialisierung nie "neu konfiguriert" - in diesem Fall ist es sinnvoll, es endgültig zu machen, um sicherzustellen, dass niemand es ändern kann (durch Fehler oder auf andere Weise). Natürlich, wenn Sie a verwenden wollenLoggerAuf eine andere Art und Weise müssen Sie möglicherweise NICHT verwenden static final- aber ich wage zu vermuten, dass 80% der Apps die Protokollierung wie oben erläutert verwenden würden.

Liv
quelle
3

Um diese Frage zu beantworten, sollten Sie sich gefragt haben, wofür "statisch" und "endgültig" sind.

Für einen Logger (ich nehme an, Sie sprechen über die Log4J Logger-Klasse) möchten Sie eine Kategorie pro Klasse. Dies sollte dazu führen, dass Sie es nur einmal zuweisen und nicht mehr als eine Instanz pro Klasse erforderlich ist. Und vermutlich gibt es keinen Grund, das Logger-Objekt einer Klasse einer anderen auszusetzen. Warum also nicht privat machen und einigen OO-Prinzipien folgen?

Beachten Sie auch, dass der Compiler davon profitieren kann. Ihr Code ist also etwas besser :)

Daniel Leschkowski
quelle
2

Denn dies ist normalerweise die Art von Funktionalität, die für alle Instanzen Ihrer Objekte gemeinsam genutzt werden kann. Es ist nicht sehr sinnvoll (in 90% der Fälle), für zwei Instanzen derselben Klasse einen anderen Logger zu haben.

Manchmal sehen Sie jedoch auch Logger-Klassen, die als Singletons deklariert sind oder einfach statische Funktionen zum Protokollieren Ihrer Daten anbieten.

Vincent Mimoun-Prat
quelle
2

Dieser Code ist anfällig, aber nach Java7 können wir Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); anstelle des statischen Loggers verwenden.

nkduqi
quelle
This is code is vulnerableKönnten Sie klarstellen, dass Sie ein bisschen antworten?
Dmitry Zagorulkin
1

In den meisten Fällen werden Sie die Referenz nicht ändern, und der finalModifikator markiert sie. Sie benötigen nicht für jede Klasseninstanz separate Instanzen static. Und dies dient in erster Linie der Leistung - es kann gut optimiert werden (endgültig) und spart Speicher (statisch).

zacheusz
quelle
1

Im Idealfall sollte Logger bis Java 7 wie folgt sein, um kein Sonar und einen kompatiblen Code anzugeben: privat: Niemals außerhalb der übergeordneten Klasse zugänglich sein. Wenn eine andere Klasse etwas protokollieren muss, sollte sie ihren eigenen Logger instanziieren. statisch: nicht abhängig von einer Instanz einer Klasse (einem Objekt). Wenn Sie etwas protokollieren, können natürlich Kontextinformationen in den Nachrichten bereitgestellt werden, aber der Logger sollte auf Klassenebene erstellt werden, um zu verhindern, dass zusammen mit jedem Objekt ein Logger erstellt wird und somit ein hoher Speicherbedarf vermieden wird. final: einmal und nur einmal pro Klasse erstellt werden.

Kratika Chaurasia
quelle
0

Zusätzlich zu den in den anderen Antworten angegebenen Gründen stieß ich auf Folgendes, wenn mein Logger weder statisch noch endgültig war:

...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);

public String toJson() {
  GsonBuilder gsonBuilder = new GsonBuilder();   
  return gsonBuilder.create().toJsonTree(this).toString();
}
...

In bestimmten Fällen (wenn ich die Gson-Bibliothek verwendete) wurde eine Stackoverflow-Ausnahme angezeigt. Meine spezielle Situation bestand darin, die Klasse zu instanziieren, die den nicht statischen nicht endgültigen Logger enthält. Rufen Sie dann die toJson-Methode auf, die GsonBuilder aufgerufen hat:

...
DataSummary ds = new DataSummary(data);    
System.out.println(ds.toJson());
...
Paul
quelle
0

Tatsächlich können statische Logger "schädlich" sein, da sie in einem statischen Kontext arbeiten sollen. In einer dynamischen Umgebung, z. OSGi kann es hilfreich sein, nicht statische Logger zu verwenden. Da einige Protokollierungsimplementierungen das interne Zwischenspeichern von Protokollierern durchführen (AFAIK mindestens log4j), können die Auswirkungen auf die Leistung vernachlässigbar sein.

Ein Nachteil von statischen Loggern ist z. Speicherbereinigung (wenn eine Klasse nur einmal verwendet wird, z. B. während der Initialisierung, bleibt der Logger weiterhin in der Nähe).

Weitere Details finden Sie unter:

Siehe auch:

ViToni
quelle
0

Nach den Informationen, die ich aus dem Internet darüber gelesen habe, ob der Logger statisch ist oder nicht, ist es die beste Vorgehensweise, ihn entsprechend den Anwendungsfällen zu verwenden.

Es gibt zwei Hauptargumente:

1) Wenn Sie es statisch machen, wird kein Müll gesammelt (Speichernutzung und Leistung).

2) Wenn Sie es nicht statisch machen, wird es für jede Klasseninstanz erstellt (Speichernutzung)

Wenn Sie also einen Logger für einen Singleton erstellen, müssen Sie ihn nicht statisch machen. Weil es nur eine Instanz gibt, also einen Logger.

Wenn Sie dagegen einen Logger für ein Modell oder eine Entitätsklasse erstellen, sollten Sie es statisch machen, keine doppelten Logger zu erstellen.

Bahadir Tasdemir
quelle
-1

Sie benötigen weiterhin einen statischen Logger für innere statische Klassen

Al Emu
quelle