Grüße, liebe Freunde!
Ich möchte meine Gedanken zum Thema Protokollierung und deren Auswirkungen teilen.
Möglicherweise war die Protokollierung aufgrund mangelnder theoretischer Forschung in der Java-Welt schon immer eine turbulente Zone. Im Laufe der Zeit sind mehrere Bibliotheken für die Protokollierung entstanden, z.
- Log4j
- Java Util-Protokollierung
- Commons-Protokollierung
- Logback
- Log4j2
Bei dem Versuch, den Rest des Restes einzugrenzen, führte leider jeder seine eigenen Mängel ein.
Und wenn sich aus Sicht der Codestandardisierung die Situation nach dem Erscheinen von Slf4j - als Abstraktionsschicht für die Protokollierung - verbessert hat, bestehen in bestehenden Implementierungen immer noch ungelöste Probleme.
Als Open Source-Community ergreifen wir die Initiative, um einen neuen, revolutionären Ansatz zu entwickeln - und mithilfe der neuesten Entwicklungen wie Skripten einen leichten (aber gleichzeitig funktionsreichen) Logger zu erstellen.
Die Probleme
- Bestehende Implementierungen bieten nur teilweise Unterstützung für Skripte in den Einstellungen
Dies führt zu einer deklarativen Programmierung in den Logger-Konfigurationsdateien (XML, JSON, YAML), obwohl es viel einfacher wäre, Konfigurationswerte zur Laufzeit mithilfe von Imperative Scripting dynamisch zu interpretieren.
Nehmen wir ein Beispiel für eine Filterkonfiguration in Logback, um nur Nachrichten mit der Protokollierungsstufe INFO zu protokollieren:
<filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
Dies ist ein typisches Beispiel für deklarative XML-Programmierung.
(Ja, Logback unterstützt einen Filter mit Groovy, gilt jedoch nur für bestimmte Appender, nicht für den Logger.)
Die Skriptunterstützung für die Formatierung der Zeichenfolge fehlt jedoch vollständig.
- Komplizierte und überlange Konfiguration
Nehmen Sie Logback und Log4j2:
Es gibt keine Möglichkeit, die Protokollierungsstufe für einen bestimmten Appender zu konfigurieren.
Appender werden getrennt von Loggern konfiguriert, und Logger beziehen sich mit dem Attribut „AppenderRef“ auf Appender. Nur Logger unterstützen das Festlegen der Protokollierungsstufe und der Klassennamen.
Angenommen, wir müssen Debug-Nachrichten von einer Foo-Klasse aus einer bestimmten Protokolldatei ausschließen, ohne andere Protokolldateien und -klassen zu beeinflussen.
In Logback ist dies mithilfe des Groovy Script-Filters im Appender möglich. Wenn jedoch viele Appender vorhanden sind, nimmt die Größe der Konfiguration exponentiell zu.
- Zu jeder Protokollierungsstufe - eine separate Datei!
Wir konnten die Möglichkeit einer solchen Einstellung nicht finden, bei der Nachrichten nach Nachrichtenebene (Debug, Info usw.) in Dateien gruppiert werden.
Bestehende Funktionen erfordern das Duplizieren von Appendern auf jeder Protokollierungsstufe.
- Festlegen der Filterung nach Klassennamen im Root-Logger
Der Root-Logger unterstützt nur das Festlegen der Protokollierungsstufe, es besteht jedoch keine Möglichkeit der zentralen Steuerung, welche Klassen protokolliert werden sollen.
- Es besteht eine konzeptionelle Trennung zwischen der Generierung der Protokolldaten in der Anwendung und der Verwendung dieser Daten durch den Protokollierer
Die historische Praxis ist so, dass Logger (und ihre Konfiguration) klassenzentrierter sind als wenn sie dateizentriert wären.
Dies widerspricht der menschlichen Wahrnehmung, die die Erwartungen an den endgültigen Inhalt der Protokolldateien logischer wahrnimmt, als sich Gedanken über die Einrichtung jeder einzelnen Klasse zu machen.
In der Praxis ist dieses Paradoxon der Grund für die funktionalen Einschränkungen bestehender Implementierungen:
- Komplizierte Konfiguration des Dateinamens
- Irrationale Konfiguration des Loggers, zum Beispiel:
Logback unterstützt maximal 1 "Diskriminator" in "SiftingAppender".
SiftingAppender hat Einschränkungen in den Richtlinieneinstellungen für die Archivierung
Überarbeiteter RoutingAppender in Log4j2
Lösung
- Volle Skriptunterstützung in der Konfiguration
Bobbin verwendet die Konfiguration als Locator für Groovy-Skripte, die das Verhalten des Loggers zur Laufzeit der Anwendung bestimmen.
So sieht das Beispiel „Filter“ aus:
{ "levels": "['info'].contains(level)" }
Jeder Aspekt des Loggers unterstützt die Anpassung mithilfe von Skripten:
- Protokollierungsstufen
- Klassennamen
- Nachrichtenformat
- Dateinamen
- Einfache und übersichtliche Einrichtung
Bobbin benötigt keine Encoder, Patterns, Filter, Diskriminatoren und viele andere unnötige Dinge.
Es ist mit nur wenigen grundlegenden Parametern konfiguriert:
- Ebenen
- Klassen
- Dateien
- Zeilenformat
Separate Dateien für jede Protokollierungsstufe: Fügen Sie einfach "$ {level}" in die Dateinamenmaske in Bobbin.json (Konfigurationsdatei) ein.
Beispielkonfigurationsdatei:
{ "levels": "['debug', 'info', 'warn', 'error'].contains(level)", "destinations": [ { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/PLUGINS/INPUT/${className}/${level}/${className}_${level}.log\"" }, "classes": "className.contains('conf.plugins.input')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/PLUGINS/OUTPUT/${className}/${level}/${threadName}_${level}_${date}.log\"" }, "classes": "className.contains('conf.plugins.output')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/THREADS/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\"" }, "classes": "className.contains('io.infinite.')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/ALL/WARNINGS_AND_ERRORS_${date}.log\"" }, "levels": "['warn', 'error'].contains(level)" }, { "name": "io.infinite.bobbin.destinations.ConsoleDestination", "levels": "['warn', 'error'].contains(level)" } ] }
Probieren Sie Bobbin jetzt aus:
Gradle: compile "io.infinite:bobbin:2.0.0"
* Bobbin ist ein Open Source-Projekt, das unter Apache lizenziert ist.