Warum nicht java.util.logging verwenden?

351

Zum ersten Mal in meinem Leben befinde ich mich in einer Position, in der ich eine Java-API schreibe, die Open Source ist. Hoffentlich in vielen anderen Projekten enthalten sein.

Für die Protokollierung habe ich (und in der Tat die Leute, mit denen ich arbeite) immer JUL (java.util.logging) verwendet und hatte nie Probleme damit. Jetzt muss ich jedoch genauer verstehen, was ich für meine API-Entwicklung tun soll. Ich habe einige Nachforschungen angestellt und mit den Informationen, die ich habe, werde ich nur verwirrter. Daher dieser Beitrag.

Da ich von JUL komme, bin ich voreingenommen. Mein Wissen über den Rest ist nicht so groß.

Aufgrund meiner Recherchen habe ich folgende Gründe gefunden, warum die Leute JUL nicht mögen:

  1. „Ich begann in Java zu entwickeln , lange bevor Sun Juli veröffentlicht und es war einfach leichter für mich , mit Logging-Framework-X fortzusetzen , anstatt etwas Neues zu lernen“ . Hmm. Ich mache keine Witze, das sagen die Leute. Mit diesem Argument könnten wir alle COBOL machen. (Ich kann mich jedoch durchaus darauf beziehen, dass ich selbst ein fauler Typ bin.)

  2. "Ich mag die Namen der Protokollierungsstufen in JUL nicht" . Ok, im Ernst, das ist einfach kein Grund genug, eine neue Abhängigkeit einzuführen.

  3. "Ich mag das Standardformat der Ausgabe von JUL nicht" . Hmm. Dies ist nur eine Konfiguration. Sie müssen nicht einmal Code tun. (Richtig, früher mussten Sie möglicherweise Ihre eigene Formatter-Klasse erstellen, um es richtig zu machen).

  4. „Ich benutze andere Bibliotheken , die auch Logging-Framework-X verwenden , so dass ich dachte , es einfacher , nur dass man verwenden“ . Dies ist ein zirkuläres Argument, nicht wahr? Warum verwendet "jeder" Logging-Framework-X und nicht JUL?

  5. "Alle anderen verwenden Logging-Framework-X" . Dies ist für mich nur ein Sonderfall der oben genannten. Die Mehrheit ist nicht immer richtig.

Die wirklich große Frage ist also, warum nicht JUL? . Was habe ich vermisst? Das Grundprinzip für die Protokollierung von Fassaden (SLF4J, JCL) ist, dass es in der Vergangenheit mehrere Protokollierungsimplementierungen gegeben hat und der Grund dafür aus meiner Sicht wirklich auf die Zeit vor JUL zurückgeht. Wenn JUL perfekt wäre, gäbe es keine Holzfassaden, oder was? Um die Sache noch verwirrender zu machen, ist JUL bis zu einem gewissen Grad eine Fassade, mit der Handler, Formatierer und sogar der LogManager ausgetauscht werden können.

Sollten wir uns nicht fragen, warum sie überhaupt notwendig waren, anstatt mehrere Methoden zu nutzen, um dasselbe zu tun (Protokollierung)? (und sehen, ob diese Gründe noch existieren)

Ok, meine bisherigen Forschungen haben zu ein paar Dingen geführt, von denen ich sehe, dass sie echte Probleme mit JUL darstellen können:

  1. Leistung . Einige sagen, dass die Leistung in SLF4J den anderen überlegen ist. Dies scheint mir ein Fall vorzeitiger Optimierung zu sein. Wenn Sie Hunderte von Megabyte pro Sekunde protokollieren müssen, bin ich mir nicht sicher, ob Sie auf dem richtigen Weg sind. JUL hat sich ebenfalls weiterentwickelt und die Tests, die Sie unter Java 1.4 durchgeführt haben, sind möglicherweise nicht mehr wahr. Sie können hier darüber lesen , und dieses Update hat es in Java 7 geschafft. Viele sprechen auch über den Overhead der Verkettung von Zeichenfolgen bei Protokollierungsmethoden. Die vorlagenbasierte Protokollierung vermeidet diese Kosten und ist auch in JUL vorhanden. Persönlich schreibe ich nie wirklich vorlagenbasierte Protokollierung. Dafür zu faul. Zum Beispiel, wenn ich das mit JUL mache:

    log.finest("Lookup request from username=" + username 
       + ", valueX=" + valueX
       + ", valueY=" + valueY));

    Meine IDE warnt mich und bittet um Erlaubnis, dass sie geändert werden soll in:

    log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", 
       new Object[]{username, valueX, valueY});

    .. was ich natürlich akzeptieren werde. Erlaubnis erteilt ! Danke für deine Hilfe.

    Ich schreibe solche Aussagen also nicht selbst, das wird von der IDE gemacht.

    Zusammenfassend zum Thema Leistung habe ich nichts gefunden, was darauf hindeuten würde, dass die Leistung von JUL im Vergleich zur Konkurrenz nicht in Ordnung ist.

  2. Konfiguration aus dem Klassenpfad . Out-of-the-Box JUL kann keine Konfigurationsdatei aus dem Klassenpfad laden. Es sind ein paar Codezeilen , um dies zu erreichen. Ich kann sehen, warum dies ärgerlich sein mag, aber die Lösung ist kurz und einfach.

  3. Verfügbarkeit von Ausgabe-Handlern . JUL wird mit 5 sofort einsatzbereiten Ausgabehandlern geliefert: Konsole, Dateistream, Socket und Speicher. Diese können erweitert oder neue geschrieben werden. Dies kann beispielsweise das Schreiben in UNIX / Linux Syslog und Windows Event Log sein. Ich persönlich hatte diese Anforderung noch nie und habe sie auch noch nie gesehen, aber ich kann mich durchaus darauf beziehen, warum sie möglicherweise eine nützliche Funktion ist. Logback wird beispielsweise mit einem Appender für Syslog geliefert. Trotzdem würde ich das argumentieren

    1. 99,5% des Bedarfs an Ausgabezielen werden durch den sofort einsatzbereiten JUL gedeckt.
    2. Spezielle Bedürfnisse könnten von benutzerdefinierten Handlern zusätzlich zu JUL und nicht zu etwas anderem berücksichtigt werden. Nichts deutet darauf hin, dass das Schreiben eines Syslog-Ausgabehandlers für JUL länger dauert als für ein anderes Protokollierungsframework.

Ich bin wirklich besorgt, dass ich etwas übersehen habe. Die Verwendung von Protokollierungsfassaden und anderen Protokollierungsimplementierungen als JUL ist so weit verbreitet, dass ich zu dem Schluss kommen muss, dass ich es einfach nicht verstehe. Das wäre leider nicht das erste Mal. :-)

Was soll ich mit meiner API tun? Ich möchte, dass es erfolgreich wird. Ich kann natürlich einfach "mit dem Fluss gehen" und SLF4J implementieren (was heutzutage am beliebtesten zu sein scheint), aber um meinetwillen muss ich immer noch genau verstehen, was mit dem heutigen JUL falsch ist, der all den Flaum rechtfertigt? Werde ich mich selbst sabotieren, indem ich JUL für meine Bibliothek wähle?

Leistung testen

(Abschnitt hinzugefügt von nolan600 am 07-JUL-2012)

Im Folgenden wird von Ceki darauf hingewiesen, dass die Parametrisierung von SLF4J zehnmal oder schneller als die von JUL ist. Also habe ich angefangen, einige einfache Tests durchzuführen. Auf den ersten Blick ist die Behauptung sicherlich richtig. Hier sind die vorläufigen Ergebnisse (aber lesen Sie weiter!):

  • Ausführungszeit SLF4J, Backend Logback: 1515
  • Ausführungszeit SLF4J, Backend JUL: 12938
  • Ausführungszeit JUL: 16911

Die obigen Zahlen sind ms, also ist weniger besser. Der 10-fache Leistungsunterschied ist also zunächst ziemlich eng. Meine erste Reaktion: Das ist viel!

Hier ist der Kern des Tests. Wie zu sehen ist, werden eine Ganzzahl und eine Zeichenfolge in einer Schleife zusammengefasst, die dann in der Protokollanweisung verwendet wird:

    for (int i = 0; i < noOfExecutions; i++) {
        for (char x=32; x<88; x++) {
            String someString = Character.toString(x);
            // here we log 
        }
    }

(Ich wollte, dass die Protokollanweisung sowohl einen primitiven Datentyp (in diesem Fall ein int) als auch einen komplexeren Datentyp (in diesem Fall einen String) hat. Ich bin mir nicht sicher, ob es wichtig ist, aber da haben Sie es.)

Die Protokollanweisung für SLF4J:

logger.info("Logging {} and {} ", i, someString);

Die Protokollanweisung für JUL:

logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});

Die JVM wurde mit demselben Test "aufgewärmt", der einmal ausgeführt wurde, bevor die eigentliche Messung durchgeführt wurde. Java 1.7.03 wurde unter Windows 7 verwendet. Die neuesten Versionen von SLF4J (v1.6.6) und Logback (v1.0.6) wurden verwendet. Stdout und stderr wurden auf das Nullgerät umgeleitet.

Es stellt sich jedoch heraus, dass JUL die meiste Zeit damit verbringt, getSourceClassName()da JUL standardmäßig den Namen der Quellklasse in der Ausgabe druckt, während Logback dies nicht tut. Also vergleichen wir Äpfel und Orangen. Ich muss den Test erneut durchführen und die Protokollierungsimplementierungen auf ähnliche Weise konfigurieren, damit sie tatsächlich dasselbe Material ausgeben. Ich vermute jedoch, dass SLF4J + Logback immer noch die Nase vorn hat, aber weit von den oben angegebenen Anfangszahlen entfernt ist. Bleib dran.

Übrigens: Der Test war das erste Mal, dass ich tatsächlich mit SLF4J oder Logback gearbeitet habe. Eine angenehme Erfahrung. JUL ist sicherlich viel weniger einladend, wenn Sie anfangen.

Testleistung (Teil 2)

(Abschnitt hinzugefügt von nolan600 am 08-JUL-2012)

Wie sich herausstellt, spielt es für die Leistung keine Rolle, wie Sie Ihr Muster in JUL konfigurieren, dh ob es den Quellennamen enthält oder nicht. Ich habe es mit einem sehr einfachen Muster versucht:

java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

und das änderte die obigen Zeiten überhaupt nicht. Mein Profiler stellte fest, dass der Logger immer noch viel Zeit mit Anrufen verbrachte, getSourceClassName()auch wenn dies nicht Teil meines Musters war. Das Muster spielt keine Rolle.

Ich komme daher zu dem Thema Leistung, dass zumindest für die getestete vorlagenbasierte Protokollanweisung der tatsächliche Leistungsunterschied zwischen JUL (langsam) und SLF4J + Protokollierung (schnell) ungefähr um den Faktor 10 zu liegen scheint. Genau wie Ceki sagte.

Ich kann auch eine andere Sache sehen, nämlich dass der getLogger()Anruf von SLF4J viel teurer ist als der von JUL. (95 ms vs 0,3 ms, wenn mein Profiler genau ist). Das macht Sinn. SLF4J muss einige Zeit für die Bindung der zugrunde liegenden Protokollierungsimplementierung aufwenden. Das macht mir keine Angst. Diese Aufrufe sollten während der Lebensdauer einer Anwendung eher selten sein. Die Echtheit sollte in den eigentlichen Protokollaufrufen enthalten sein.

Schlußfolgerung

(Abschnitt hinzugefügt von nolan600 am 08-JUL-2012)

Vielen Dank für all Ihre Antworten. Im Gegensatz zu dem, was ich ursprünglich dachte, habe ich mich letztendlich für SLF4J für meine API entschieden. Dies basiert auf einer Reihe von Dingen und Ihrer Eingabe:

  1. Es bietet Flexibilität bei der Auswahl der Protokollimplementierung zur Bereitstellungszeit.

  2. Probleme mit mangelnder Flexibilität der JUL-Konfiguration bei der Ausführung auf einem Anwendungsserver.

  3. SLF4J ist sicherlich viel schneller als oben beschrieben, insbesondere wenn Sie es mit Logback koppeln. Auch wenn dies nur ein grober Test war, habe ich Grund zu der Annahme, dass bei SLF4J + Logback viel mehr Anstrengungen zur Optimierung unternommen wurden als bei JUL.

  4. Dokumentation. Die Dokumentation für SLF4J ist einfach viel umfassender und präziser.

  5. Musterflexibilität. Während ich die Tests durchführte, wollte ich, dass JUL das Standardmuster von Logback nachahmt. Dieses Muster enthält den Namen des Threads. Es stellt sich heraus, dass JUL dies nicht sofort tun kann. Ok, ich habe es bis jetzt nicht verpasst, aber ich denke nicht, dass es etwas ist, das in einem Protokoll-Framework fehlen sollte. Zeitraum!

  6. Die meisten (oder viele) Java-Projekte verwenden heutzutage Maven, daher ist das Hinzufügen einer Abhängigkeit nicht so wichtig, insbesondere wenn diese Abhängigkeit ziemlich stabil ist, dh ihre API nicht ständig ändert. Dies scheint für SLF4J zu gelten. Auch das SLF4J-Glas und seine Freunde sind klein.

Das Seltsame war also, dass ich mich über JUL ziemlich aufgeregt habe, nachdem ich ein bisschen mit SLF4J gearbeitet hatte. Ich bedaure immer noch, dass es bei JUL so sein muss. JUL ist alles andere als perfekt, macht aber irgendwie den Job. Nur nicht gut genug. Das Gleiche kann Propertiesals Beispiel angeführt werden, aber wir denken nicht daran, dies zu abstrahieren, damit die Leute ihre eigene Konfigurationsbibliothek anschließen können und was Sie haben. Ich denke, der Grund dafür ist, dass es Propertiesknapp über der Latte liegt, während das Gegenteil für JUL von heute gilt ... und in der Vergangenheit bei Null, weil es nicht existierte.

Peterh
quelle
8
Ich werde keinen Abschluss fragen, da diese gut präsentierte Frage interessant ist, aber es ist grenzwertig, wenn Sie die FAQ lesen: Es wird schwierig sein, eine endgültige eindeutige Antwort zu finden, die nicht auf Meinungen basiert.
Denys Séguret
Was Sie vielleicht übersehen haben, ist, dass viele Framework-Autoren den Versuch, JUL zu verwenden, aufgegeben haben und es daher oft schwieriger ist, es zu verwenden, wenn Sie nicht einfach Vanille-Java erstellen.
Denys Séguret
3
Es ist irreführend, den Oberbegriff "Logging-Framework-X" zu verwenden, wenn auf beliebte Logging-Frameworks vor Juli Bezug genommen wird. In diesem Fall sollten Sie "log4j" verwenden. Andere beliebte Frameworks wie SLF4J und Logback kamen lange nach der Veröffentlichung von Jul.
Ceki
1
@ Acuariano. Das Netty-Projekt verwendet einfach Reflection, um zu testen, welches Protokollierungsframework auf dem Klassenpfad verfügbar ist. Siehe hier für die Quelle. Siehe InternalLoggerFactory.java.
Peterh
1
@xenoterracide noch wichtiger wäre ein Update auf Java 9, wie es eingeführt java.lang.System.Loggerwurde. Hierbei handelt es sich um eine Schnittstelle , die auf das gewünschte Protokollierungsframework umgeleitet werden kann, sofern dieses Framework aufholt und eine Implementierung dieser Schnittstelle bereitstellt. In Kombination mit der Modularisierung können Sie sogar eine Anwendung mit einer gebündelten JRE bereitstellen, die keine enthält java.util.logging, wenn Sie ein anderes Framework bevorzugen.
Holger

Antworten:

207

Haftungsausschluss : Ich bin der Gründer von log4j-, SLF4J- und logback-Projekten.

Es gibt objektive Gründe, SLF4J zu bevorzugen. Zum einen gibt SLF4J dem Endbenutzer die Freiheit, das zugrunde liegende Protokollierungsframework auszuwählen . Darüber hinaus bevorzugen versierte Benutzer Logback, das Funktionen bietet, die über log4j hinausgehen , wobei Jul weit zurückfällt . In Bezug auf Funktionen kann Juli für einige Benutzer ausreichend sein, für viele andere jedoch nicht. Kurz gesagt, wenn die Protokollierung für Sie wichtig ist, möchten Sie SLF4J mit Logback als zugrunde liegende Implementierung verwenden. Wenn die Protokollierung unwichtig ist, ist Juli in Ordnung.

Als Oss-Entwickler müssen Sie jedoch die Vorlieben Ihrer Benutzer berücksichtigen und nicht nur Ihre eigenen. Daraus folgt, dass Sie SLF4J nicht einführen sollten, weil Sie davon überzeugt sind, dass SLF4J besser als jul ist, sondern weil die meisten Java-Entwickler derzeit (Juli 2012) SLF4J als Protokollierungs-API bevorzugen. Wenn Sie sich letztendlich nicht für die Meinung der Bevölkerung interessieren, sollten Sie die folgenden Fakten berücksichtigen:

  1. Diejenigen, die Jul bevorzugen, tun dies aus Bequemlichkeit, da Jul mit dem JDK gebündelt ist. Meines Wissens gibt es keine anderen objektiven Argumente für Jul
  2. Ihre eigene Präferenz für Juli ist genau das, eine Präferenz .

Daher ist es in diesem Fall ein logischer Irrtum, "harte Fakten" über der öffentlichen Meinung zu halten, obwohl dies scheinbar mutig ist.

Wenn immer noch nicht überzeugt, macht JB Nizet ein zusätzliches und schlagkräftiges Argument:

Es sei denn, der Endbenutzer hätte diese Anpassung bereits für seinen eigenen Code oder eine andere Bibliothek vornehmen können, die log4j oder logback verwendet. jul ist erweiterbar, aber logback, jul, log4j und Gott weiß nur, welches andere Protokollierungsframework erweitert werden muss, da er vier Bibliotheken verwendet, die vier verschiedene Protokollierungsframeworks verwenden, ist umständlich. Mit SLF4J können Sie die gewünschten Protokollierungsframeworks konfigurieren, nicht das von Ihnen ausgewählte. Denken Sie daran, dass ein typisches Projekt unzählige Bibliotheken verwendet und nicht nur Ihre .

Wenn Sie aus irgendeinem Grund die SLF4J-API hassen und ihre Verwendung den Spaß an Ihrer Arbeit zunichte macht, dann entscheiden Sie sich auf jeden Fall für jul. Schließlich gibt es Mittel, um jul auf SLF4J umzuleiten .

Übrigens ist die Jul-Parametrisierung mindestens zehnmal langsamer als die von SLF4J, was einen spürbaren Unterschied macht.

Ceki
quelle
2
@Ceki Vielleicht möchten Sie Ihren Haftungsausschluss etwas näher erläutern, damit er Ihre aktuelle Rolle in den Projekten log4j, slf4j und logback erwähnt. Der Grund ist natürlich, Ihre Voreingenommenheit zu erklären.
Thorbjørn Ravn Andersen
2
Gibt es eine gewisse Unterstützung für die Behauptung, dass die meisten Java-Entwickler SLF4J als Protokollierungs-API bevorzugen?
Olivier Cailloux
3
Das Wesentliche an meinem Beitrag ist, dass verschiedene Entwickler unterschiedliche Vorlieben haben, was unbestritten zu sein scheint. Ja?
Ceki
1
Ehrlich gesagt würde ich gerne 2018 Benchmarks für Java 11 (oder was auch immer das sein mag) und gegen log4j2 im asynchronen Modus sehen.
Xenoterracide
5
Hier verwende ich SLF4J und muss mich noch mit allen anderen Protokollierungsframeworks befassen, die andere Bibliotheken verwenden. Die Verwendung von SLF4J löst das Problem heterogener Logger nicht, sondern macht es nur noch schlimmer. xkcd.com/927
Charlie
34
  1. java.util.loggingwurde in Java 1.4 eingeführt. Zuvor gab es Verwendungszwecke für die Protokollierung. Deshalb gibt es viele andere Protokollierungs-APIs. Diese APIs wurden vor Java 1.4 stark genutzt und hatten daher einen großartigen Marktanteil, der bei der Veröffentlichung von 1.4 nicht nur auf 0 fiel.

  2. JUL hat nicht so toll angefangen, viele der Dinge, die Sie erwähnt haben, waren in 1.4 viel schlimmer und wurden erst in 1.5 besser (und ich denke auch in 6, aber ich bin mir nicht sicher).

  3. JUL eignet sich nicht für mehrere Anwendungen mit unterschiedlichen Konfigurationen in derselben JVM (denken Sie an mehrere Webanwendungen, die nicht interagieren sollten). Tomcat muss durch einige Reifen springen, damit das funktioniert (JUL effektiv neu implementieren, wenn ich das richtig verstanden habe).

  4. Sie können nicht immer beeinflussen, welches Protokollierungsframework Ihre Bibliotheken verwenden. Daher hilft die Verwendung von SLF4J (das eigentlich nur eine sehr dünne API-Schicht über anderen Bibliotheken ist) dabei, ein einigermaßen konsistentes Bild der gesamten Protokollierungswelt zu erhalten (sodass Sie das zugrunde liegende Protokollierungsframework festlegen können, während sich die Bibliothek weiterhin im selben System protokolliert).

  5. Bibliotheken können sich nicht leicht ändern. Wenn eine frühere Version einer Bibliothek zur Verwendung von Protokollierungsbibliothek-X verwendet wurde, kann sie nicht einfach zu Protokollierungsbibliothek-Y (z. B. JUL) wechseln, selbst wenn letztere eindeutig überragend ist: Jeder Benutzer dieser Bibliothek müsste lernen das neue Protokollierungsframework und (zumindest) die Protokollierung neu konfigurieren. Das ist ein großes Nein-Nein, besonders wenn es den meisten Menschen keinen offensichtlichen Gewinn bringt.

Trotzdem denke ich, dass JUL heutzutage zumindest eine gültige Alternative zu anderen Protokollierungsframeworks ist.

Joachim Sauer
quelle
1
Danke Joachim, ich schätze deinen Beitrag. Ihre (1) und (2) sind für mich nur Geschichte. Vor langer Zeit. Ihre (4) ist eine Folge davon und wird dann zu dem, was ich als zyklisches Argument bezeichne. Ihre (3) ist jedoch wirklich interessant. Vielleicht hast du etwas vor? Dies würde jedoch nur diejenigen betreffen, die Anwendungscontainer bauen, bei denen es sich letztendlich nur um sehr wenige Personen handelt. Oder was?
Peterh
3
Nun, wer die Geschichte ignoriert, ist dazu verdammt, sie zu wiederholen ;-) Die Geschichte ist in der Softwareentwicklung sehr relevant. Die Leute bewegen sich nicht zu schnell und das Ersetzen vorhandener Bibliotheken von Drittanbietern durch Standard-APIs funktioniert nur dann gut, wenn die Standard-APIs mindestens so gut funktionieren wie die Bibliotheken von Drittanbietern. Und sie haben es anfangs nicht getan (und in einigen Fällen wohl immer noch nicht).
Joachim Sauer
Joachim, ich interessiere mich für die "in einigen Fällen wohl immer noch nicht", die Sie erwähnen. Dort muss das Fleisch sein. Das Ersetzen einer Logger-Bibliothek in Ihrem vorhandenen Code ist ziemlich trivial und kann heutzutage automatisiert werden. SLF4J hat ein Werkzeug für das, was meinen Standpunkt beweist. Ich würde also denken, dass eine riesige Bibliothek, die 2002 mit log4j geschrieben wurde, mit einem automatisierten Tool in wenigen Minuten in JUL konvertiert werden kann. (Ich weiß allerdings nicht, ob es eine gibt). Warum passiert es nicht?
Peterh
3
@ nolan6000: Ich weiß nicht genug über die Einzelheiten, um auf Details zu diesem Satz einzugehen, und es ist nicht wirklich der Punkt, den ich mache. Auch wenn JUL jetzt mit Frameworks von Drittanbietern vergleichbar ist, sind Trägheit und vorhandene Infrastruktur immer noch ein wichtiger Grund, nicht zu wechseln. Wenn beispielsweise Bibliothek X in Version 1.1 slf4j verwendet, wäre der Wechsel zu JUL in 1.2 (oder sogar 2.0) ein großes Problem für viele Benutzer (die das alte System bereits korrekt konfiguriert haben und dies ohne erkennbaren Gewinn erneut durchführen müssten). .
Joachim Sauer
@ nolan6000 Auch wenn Sie sich nicht für den Verlauf interessieren, tun dies die Bibliotheken , die Sie in Ihren Anwendungen verwenden, mit Sicherheit. Es macht keinen Spaß, eine Bibliothek zu verwerfen, nur weil sie ein anderes Protokollierungsframework als Sie verwendet hat.
Thorbjørn Ravn Andersen
29

Meiner Meinung nach besteht der Hauptvorteil bei der Verwendung einer Protokollierungsfassade wie slf4j darin, dass Sie dem Endbenutzer der Bibliothek die Wahl der konkreten Protokollierungsimplementierung überlassen, die er möchte, anstatt dem Endbenutzer Ihre Wahl aufzuerlegen.

Vielleicht hat er Zeit und Geld in Log4j oder LogBack (spezielle Formatierer, Appender usw.) investiert und zieht es vor, Log4j oder LogBack weiterhin zu verwenden, anstatt jul zu konfigurieren. Kein Problem: slf4j erlaubt das. Ist es eine kluge Wahl, Log4j über Juli zu verwenden? Vielleicht, vielleicht nicht. Aber es ist dir egal. Lassen Sie den Endbenutzer auswählen, was er bevorzugt.

JB Nizet
quelle
Danke JB. Meine Frage ist, ob ich dem Benutzer / Implementierer meiner Bibliothek wirklich so viel aufzwinge, indem ich ihm JUL aufzwinge? Wenn er zum Beispiel mit den Standard-Ausgabe-Handlern von JUL unzufrieden ist, kann er sie zur Bereitstellungszeit einfach gegen seine eigenen austauschen, wie ich es sehe. Ich sehe JUL nicht wirklich als Zwangsjacke. Es scheint mir so flexibel und erweiterbar zu sein wie die anderen.
Peterh
12
Es sei denn, der Endbenutzer hätte diese Anpassung bereits für seinen eigenen Code oder eine andere Bibliothek vornehmen können, die log4j oder LogBack verwendet. jul ist erweiterbar, aber LogBack, jul, log4j und Gott wissen nur, welches andere Protokollierungsframework erweitert werden muss, da er 4 Bibliotheken verwendet, die 4 verschiedene Protokollierungsframeworks verwenden, ist umständlich. Mit slf4j können Sie die gewünschten Protokollierungsframeworks konfigurieren. nicht der, den du gewählt hast. Denken Sie daran, dass typische Projekte unzählige Bibliotheken verwenden und nicht nur Ihre.
JB Nizet
6

Ich habe, wie Sie vermuten, mit JUL angefangen, weil es am einfachsten war, sofort loszulegen. Im Laufe der Jahre wünschte ich mir jedoch, ich hätte etwas mehr Zeit mit der Auswahl verbracht.

Mein Hauptproblem ist jetzt, dass wir eine beträchtliche Menge an 'Bibliotheks'-Code haben, der in vielen Anwendungen verwendet wird und alle JUL verwenden. Immer wenn ich diese Tools in einer Webdienst-App verwende, verschwindet die Protokollierung einfach oder geht an einen unvorhersehbaren oder seltsamen Ort.

Unsere Lösung bestand darin, dem Bibliothekscode eine Fassade hinzuzufügen, die bedeutete, dass sich die Aufrufe des Bibliotheksprotokolls nicht änderten, sondern dynamisch auf den verfügbaren Protokollierungsmechanismus umgeleitet wurden. Wenn sie in einem POJO-Tool enthalten sind, werden sie an JUL weitergeleitet, aber wenn sie als Web-App bereitgestellt werden, werden sie an LogBack umgeleitet.

Wir bedauern natürlich, dass der Bibliothekscode keine parametrisierte Protokollierung verwendet, diese kann jedoch bei Bedarf nachgerüstet werden.

Wir haben slf4j verwendet, um die Fassade zu bauen.

OldCurmudgeon
quelle
1
Gibt es einen Grund, warum Sie nicht einfach das Paket "java.util.logging nach slf4j umleiten" in der slf4j-Distribution verwendet haben?
Thorbjørn Ravn Andersen
2
Wir haben es getan, aber zu wenig Wert, da der Hauptvorteil der Umstellung auf slf4j die effiziente parametrisierte Protokollierung ist. Wenn wir das von Anfang an genutzt hätten, hätten wir jetzt keine Arbeit zu erledigen gehabt.
OldCurmudgeon
1
Ich bin damit einverstanden, dass dies die niedrig hängende Frucht von slf4j ist.
Thorbjørn Ravn Andersen
3

Ich habe jul gegen slf4j-1.7.21 über logback-1.1.7 ausgeführt und auf eine SSD, Java 1.8, Win64 ausgegeben

Juli lief 48449 ms, Logback 27185 ms für eine 1M-Schleife.

Ein bisschen mehr Geschwindigkeit und eine etwas schönere API sind für mich jedoch keine 3 Bibliotheken und 800 KB wert.

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

und

package log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}
weberjn
quelle
3
Sie vergleichen nicht Gleiches für Gleiches. Warum erstellen Sie explizit ein Array für jul? Ich denke, das liegt daran, dass slf4j keine Überladung mit einem Argument von hat logger.info(). Sie lähmen also absichtlich die Jul-Leistung, um einen Mangel in der Benutzeroberfläche von slf4j auszugleichen. Sie sollten stattdessen beide Methoden so codieren, wie sie idiomatisch codiert sind.
Klitos Kyriacou
2
Du hast es falsch verstanden. Sie müssen keine zusätzlichen 800K verwenden. Der Konsens ist, dass es sich lohnt , die sehr dünne SLF4J-API zu verwenden, da Sie (oder andere, die Ihren Code vielleicht eines Tages wiederverwenden!) Frei zwischen JUL, Logback, Log4j usw. wechseln können. SLF4J ist nur ~ 28K. Die Brücke zwischen SLF4J und JUL (slf4j-jdk ... jar) beträgt nur ~ 9K.
Riskop