Manchmal, wenn ich meinen Protokollcode sehe, frage ich mich, ob ich es richtig mache. Es gibt vielleicht keine endgültige Antwort darauf, aber ich habe folgende Bedenken:
Bibliotheksklassen
Ich habe mehrere Bibliotheksklassen, die möglicherweise einige INFO
Nachrichten protokollieren . Schwerwiegende Fehler werden als Ausnahmen gemeldet. Derzeit habe ich eine statische Protokollierungsinstanz in meinen Klassen mit dem Klassennamen als Protokollierungsnamen. (Log4j ist: Logger.getLogger(MyClass.class)
)
Ist das der richtige Weg? Möglicherweise möchte der Benutzer dieser Bibliotheksklasse keine Nachrichten von meiner Implementierung oder möchte sie in ein anwendungsspezifisches Protokoll umleiten. Sollte ich dem Benutzer erlauben, einen Logger von der "Außenwelt" aus einzustellen? Wie gehen Sie mit solchen Fällen um?
Allgemeine Protokolle
In einigen Anwendungen möchten meine Klassen möglicherweise eine Protokollnachricht in ein bestimmtes Protokoll schreiben, das nicht durch den Klassennamen gekennzeichnet ist. (Dh :) HTTP Request log
Was ist der beste Weg, so etwas zu tun? Ein Suchdienst kommt mir in den Sinn ...
Das Folgende sind die Richtlinien, die ich in all meinen Projekten befolge, um eine gute Leistung sicherzustellen. Ich bin gekommen, um diese Richtlinien auf der Grundlage der Eingaben aus verschiedenen Quellen im Internet zu erstellen.
Nach wie vor glaube ich, dass Log4j 2 bei weitem die beste Option für die Anmeldung in Java ist.
Die Benchmarks finden Sie hier . Die Praxis, die ich befolge, um die beste Leistung zu erzielen, ist wie folgt:
Verwenden Sie keine String-Verkettung. Verwenden Sie die parametrisierte Nachricht wie oben gezeigt
Verwenden Sie das dynamische Neuladen der Protokollierungskonfiguration, damit die Anwendung die Änderungen in der Protokollierungskonfiguration automatisch neu lädt, ohne dass die Anwendung neu gestartet werden muss
Verwenden Sie nicht
printStackTrace()
oderSystem.out.println()
Die Anwendung sollte den Logger vor dem Beenden herunterfahren:
quelle
if (LOGGER.isDebugEnabled()) ...
sollten überhaupt als veraltet angesehen werden.In der Antwort von @cletus schrieb er über das Problem von
if (log.isDebugEnabled()) { log.debug("val is " + value); }
Dies könnte durch die Verwendung von SLF4J überwunden werden . Es bietet eine Formatierungshilfe
log.debug("val is {}", value);
Dabei wird die Nachricht nur erstellt, wenn die Ebene debuggt.
Also, nowaday, mit SL4J und seine Begleiter Logger, Logback wird empfohlen , für die Leistung und Stabilitätsgründen.
quelle
value
zu einer Methode :getValue()
. Und die Methode könnte viel Zeit kosten. Haben dieif (log.isDebugEnabled()) {log.debug("val is " + getValues());}
gleichen Kosten wielog.debug("val is {}", getValue());
Supplier
. Schauen Sie sich diesen Blog-Beitrag an, um einige Beispiele mit Log4j zu sehen.In Bezug auf das Instanziieren von Loggern hatte ich einige Erfolge bei der Verwendung einer Eclipse Java-Vorlage zum Einrichten meiner Logger:
private static Logger log = Logger.getLogger(${enclosing_type}.class);
Dies vermeidet das Problem, dass eine JVM mit Ihrem Stack-Trace herumfummelt, und reduziert (möglicherweise trivial) den Overhead, der durch das Erstellen des Stack-Trace entsteht.
Das Tolle an der Verwendung einer solchen Vorlage ist, dass Sie sie mit Ihrem Team teilen können, wenn Sie einen einheitlichen Standard für Logger festlegen möchten.
Es sieht so aus, als ob IntelliJ dasselbe Konzept für eine Vorlagenvariable unterstützt, die den Namen des umschließenden Typs darstellt. Ich sehe keine Möglichkeit, dies in NetBeans einfach zu tun.
quelle
Ich überprüfe die Protokollebenen einer Anwendung und erkenne derzeit ein Muster:
private static final Logger logger = Logger.getLogger(Things.class) public void bla() { logger.debug("Starting " + ...) // Do stuff ... logger.debug("Situational") // Algorithms for(Thing t : things) { logger.trace(...) } // Breaking happy things if(things.isEmpty){ logger.warn("Things shouldn't be empty!") } // Catching things try { ... } catch(Exception e) { logger.error("Something bad happened") } logger.info("Completed "+...) }
Eine log4j2-Datei definiert einen Socket-Appender mit einem Failover-Appender. Und ein Konsolen-Appender. Manchmal verwende ich log4j2-Marker, wenn es die Situation erfordert.
Dachte, eine zusätzliche Perspektive könnte helfen.
quelle
Die bevorzugte Option für die Art der von Ihnen beschriebenen log4j-Konfiguration ist die Verwendung der log4j-Konfigurationsdatei . Auf diese Weise können Benutzer Ihrer Implementierung genau das tun, was Sie verlangen, da sie Ihre Konfiguration später mit etwas überschreiben können, das für ihre eigene Implementierung besser geeignet ist. Sehen Sie hier für eine sehr gründliche Grundierung.
quelle
Ich habe das wahrscheinlich irgendwo gestohlen, aber es ist schön.
Es verringert das Risiko, dass Logger beim Kopieren und Einfügen von Refactoring verwechselt werden, und es ist weniger zu tippen.
In Ihrem Code:
private final static Logger logger = LoggerFactory.make();
... und in LoggerFactory:
public static Logger make() { Throwable t = new Throwable(); StackTraceElement directCaller = t.getStackTrace()[1]; return Logger.getLogger(directCaller.getClassName()); }
(Beachten Sie, dass der Stackdump während der Initialisierung ausgeführt wird. Der Stacktrace wird wahrscheinlich nicht von der JVM optimiert, es gibt jedoch keine Garantien.)
quelle
Außerdem halte ich es für wichtig, Simple Logging Facade für Java (SLF4J) ( http://www.slf4j.org/ ) zu bezeichnen. Aufgrund einiger Probleme bei der Verwendung unterschiedlicher Protokollierungsframeworks in diversifizierten Teilen eines großen Projekts ist SLF4J der De-facto-Standard zur Lösung eines Problems bei der erfolgreichen Verwaltung dieser Teile, nicht wahr?
Der zweite Gedanke: Es scheint, dass einige Aufgaben der alten Schule durch aspektorientierte Programmierung ersetzt werden können. Spring frmwrk hat eine eigene Implementierung , einen AOP-Ansatz für die Protokollierung, der hier bei StackOverflow und hier im Spring-Blog berücksichtigt wird .
quelle