ekkes corner - ekkes ecke
Logging in OSGI Enterprise Anwendungen, Teil 1
Mittwoch, 24. September 2008
Logging in einer ERP Anwendung ist wichtig und mit den modernen Logging Frameworks sollte das doch ganz einfach sein ;-)
Mein aktuelles ERP Projekt benötigt: Equinox als OSGI Framework, Eclipse Riena für Remote Services + UI, EasyBeans als EJB3 Container + JPA (Hibernate) u.v.m.
Das bedeutet, dass die unterschiedlichsten Logging-Frameworks integriert werden müssen:
*org.osgi.service.log
*org.eclipse.equinox.log (Extended from HEAD)
*org.apache.commons.logging
*org.apache.log4j
*org.slf4j
*java.util.logging (JSR47)
Wer meine Blogs bisher verfolgt hat, weiss aber, dass es nicht so leicht ist, eine saubere Loggingarchitektur zu entwerfen für eine komplexe OSGI Anwendung. Ganz aktuell wurde ich damit konfrontiert, dass der neueste Snapshot von EasyBeans eine neue Hibernate Version beinhaltet, die jetzt auf SLF4J als Logging Framework setzt.
Mein Lösungsvorschlag macht meine OSGI Anwendung unabhängig von allen Logging - Frameworks. Zunächst betrachten wir die wichtigsten Elemente und auch Unterschiede - dazu unterscheiden wir zwischen klassichen Java Logging Frameworks und OSGI Logging Services.
Klassische Java Logging Frameworks
* Apache Commons - Logging (JCL)
* Log4J - Logging
* SLF4J - Logging
* JDK - Logging (java.util.logging)
Das Logging erfolgt in der Regel wie folgt:
Definition des Loggers:
Commons-Logging:
private static Log logger = LogFactory.getLog(MyClass.class);
Log4J:
private static Logger logger = Logger.getLogger(MyClass.class.getName());
SLF4J:
private static Logger logger = LoggerFactory.getLogger(MyClass.class);
JDK:
private static Logger logger = Logger.getLogger(MyClass.class.getName());
Loggen eines Ereignisses:
logger.info(„meine Nachricht“)
Aus Performancegründen (String-Concatenation ist langsam) finden wir auch häufig
if (logger.isDebugEnabled())
logger.debug("Nachricht Teil 1" + aVar
+ "Nachricht Teil 2");
Anmerkung: Bei Verwendung von SLF4J (FAQ) kann die Abfrage wegfallen:
logger.debug("Nachricht Teil 1 {} Nachricht Teil 2", aVar);
Konfiguration des Logging - Frameworks:
Die Konfiguration der Frameworks kann programmatisch erfolgen - in den meisten Fällen werden wir aber eine Konfigurationsdatei finden - entweder als Properties oder im XML - Format.
Beispiel logback.xml:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} %msg%n</Pattern>
</layout>
</appender>
<root>
<level value="warn" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
Was ist beim Einsatz dieser klassischen Logging - Frameworks unter OSGI zu beachten ?
*wir benötigen die JARs als Bundle. Diese finden wir für Commons-Logging, LOG4J und SLF4J teils in Eclipse oder bei diversen Bundle Repositories
*das Logging selbst erfolgt wie in normalen Java Anwendungen auch
*die Konfiguration erfordert ein Fragment-Bundle
OSGI Logging Services
Unter OSGI gibt es Logging Services:
* OSGI : org.osgi.log (Standard OSGI Logging, Implementierung org.equinox.log)
* Extended: org.equinox.log (HEAD Version, wie zB mit Riena ausgeliefert, erweitertes Logging)
Das OSGI - Logging besteht aus Services und Listenern. Equinox implementiert die OSGI Log Services als ManagementServices.
*LogService / ExtendedLogService - zum Schreiben der Lognachrichten
*LogReaderService / ExtendedLogReaderService - zum Lesen der Lognachrichten
*LogListener - erhält die Lognachrichten des ReaderService
Der LogService ist mit dem klassichen Logger vergleichbar. Eine bewährte Strategie ist es, den LogService im Activator eines OSGI Bundles zu platzieren und von den Klassen des Bundles darauf zuzugreifen.
Das Loggen der Nachrichten ist dann ähnlich wie im klassischen Logging - nur müssen wir natürlich testen, ob der Service vorhanden ist:
if (logger != null) {
logger.log(LogService.LOG_INFO, „meine Nachricht“);
}
Das geloggte Ereignis kann über den LogReaderService gelesen werden. Diesen LogReaderService „trackt“ man und fügt einen eigenen LogListener hinzu. Der LogListener kann dann die Nachrichten ausgegeben oder persistieren - sei es über eines der klassischen Logging - Frameworks, einen Management Agent oder eigene Implementierungen.
Der Equinox LogService kann konfiguriert werden, um die Anzahl der im LogReader gecachten Lognachrichten und das LogLevel festzulegen. Aber wichtig: Der LogReaderService sendet unabhängig davon alle Nachrichten an die registrierten LogListener !
Klassisches Logging oder OSGI Logging ?
Betrachten wir zunächst die Unterschiede zwischen klassischem Java - Logging und OSGI - Logging Services:
a) Wann wird geloggt ?
Klassiches Logging erzeugt Lognachrichten nur dann, wenn der Logger die Frage „soll geloggt werden für my.logger.name“ mit „ja“ beantwortet, d.h. es ist abhängig von der Konfigurationsdatei, in der die Level feingranular definiert werden können.
OSGI Logging Services loggen immer alle Nachrichten, die dann über den LogReader gelesen werden können. Es ist Aufgabe des LogListener, ob und welche Ereignisse dann wirklich ausgegeben oder gespeichert werden.
b) Was wird geloggt ?
Hier die wichtigsten Inhalte des Logger - Objekts:

Die Log - Level sind nicht überall gleich und müssen ggf. gemapped werden.
Die Nachricht (Message) ist ein String, bzw. wird .toString() aufgerufen.
MDC (Mapped Diagnostic Context) - eine Map mit Thread-local Informationen
Marker ist ein „Tree“ aus Strings, mit dem Nachrichten markiert werden können.
Die sehr sinnvolle Information über Bundle und ServiceReference bekommen wir bei den OSGI LogServices automatisch geliefert. Aber auch beim Loggen über SLF4J / LOGBack können Bundle- und Service - Namen hinterlegt werden. (als Marker) Dazu später mehr.
c) Was ist besser ?
Die Frage stellt sich bei einer OSGI Enterprise - Anwendung nicht ;-)
Warum nicht ?
*Wir wissen im Vorfeld nicht, welche Projekten während des Lebenszyklus der Anwendung integriert werden.
*Wir müssen 3rdParty Bundles mit unterschiedlichsten Logging - Frameworks und -Strategien berücksichtigen.
Wir müssen also eine Antwort finden auf die Frage, WIE wir das alles integrieren können. Dann ist auch sekundär, wie wir in unseren eigenen Bundles loggen, da ja unsere Logging - Architektur mit allen Varianten umgehen kann :-)
Manchmal ist es durchaus sinnvoll, das klassische Logging und OSGI Logging zu kombinieren.
Integration aller Logging Frameworks

Kern der Lösung ist SLF4J mit einer nativen Implementierung (LOGBack).
SLF4J (Logback) führt alle klassichen Logging Frameworks zusammen: egal ob ein Bundle Commons-Logging, Log4J, JDK-Logging oder SLF4J einsetzt, alles wird transparent zur LOGBack - Implementierung geroutet.
Ebenfalls werden alle OSGI LogServices - ob Standard oder Erweitert (Extended) - über einen Listener abgefangen und an SLF4J (LOGBack) delegiert.
Abhängig von der Konfiguration gibt dann LOGBack die Nachrichten auf die Konsole, über Socket (local oder remote), in Datei(en), Datenbank(en) oder an einen LogServer aus.
(Logging) - Integration von Eclipse Riena
Beim Einsatz von Eclipse Riena M4 sind zwei kleine Probleme zu lösen:
1. Log4J-over-SLF4J
Die Bridge Log4J-over-SLF4J stellt nur das Package org.apache.log4j zur Verfügung, org.eclipse.riena.core hat aber eine Dependency zu org.apache.log4j.xml. Diesen Eintrag in der MANIFEST.MF bitte auf optional setzen.
Import-Package: org.apache.log4j,
org.apache.log4j.xml;resolution:=optional,
org.osgi.framework;version="1.3.0",
org.osgi.service.cm;version="1.2.0",
org.osgi.service.log;version="1.3.0"
2. mehrfache Logausgaben
Erst ab M5 ist Riena konfigurierbar und das Riena - Logging kann abgeschaltet werden. Unter M4 werden immer noch zwei zusätzliche Ausgaben von Rienas LogListenern auf der Console ausgegeben. (Bugzilla 247680)
(Logging) - Integration von EasyBeans OSGI
Das Logging von EasyBeans wird vollkommen transparent zu LogBack geroutet. Das seit ein paar Tagen im neuesten 1.1.0 Snapshot enthaltene Hibernate 3.4 nutzt SLF4J und ist daher ganz problemlos mit LogBack zu nutzen, das ja eine native SLF4J Implementierung ist.
weitere Informationen
Mit diesem Blog habe ich eine neue Serie gestartet, aber es ist sicher sinnvoll, auch noch meine älteren Blogs zum Thema anzusehen:
Logging (Riena - EasyBeans - Equinox) reloaded
Catch-22 Logging in OSGI Umgebungen
Links:
Simple Logging Facade for Java (SLF4J)
LOGBack - Loggingframework, native SLF4J Implementierung
Eclipse Riena (Remote Services, UI Erweiterungen)
Eclipse Equinox (OSGI Framework)
EasyBeans OSGI (EJB3 Container)
Hibernate (JPA)
Wie gehts weiter
Dieser erste Blog aus der Serie „Logging in OSGI Enterprise Anwendungen“ sollte nur einen groben Überblick geben - u.a. wurde in diesem Blog nicht detailliert angesprochen:
*Registrieren der OSGI Logging Services
*Tracken des OSGI Logging Reader Services
*Hinzufügen eines Listeners zum LogReaderService
*Details der Konfigurationsdateien
*Mapping der LogLevel
*Details der Bundles, Manifestdateien, Dependencies
*Konfiguration, Fragment-Bundles, Testen, OSGI Launch Konfigurationen
*Einsatz von EasyBeans JDBC Pooling zum persistieren der Logs in RDBMS
*Fragen zur Performance (welches Framework, klassisches Logging vs. OSGI LogServices)
*Migrationswege (wie migrieren wir unsere bestehenden Bundles / Klassen)
*Verwendung sinnvoller Eclipse PlugIns (Log4E, LogBack Konsole)
*Client-/Server Logging Strategien, Remote Services, MDC - Userinfo...
*Das „schwarze Loch“: wie logge ich, bevor alle Services zur Verfügung stehen ?
*Verpacken von Bundle- und Service - Informationen im Marker
*Was ist, wenn andere Bundles auch LogListener einsetzen und loggen ?
*...
Nicht betrachtet wurde PAX Logging unter OSGI. PAX verwendet Log4J und integriert ebenfalls verschiedene Logger (JCL, JDK, SLF4J). Mir bietet aber SLF4J mit den Markern mehr Möglichkeiten und ausserdem war mein Ziel, die Equinox OSGI LogService Erweiterungen ebenfalls nutzen zu können. PAX ist aber sicher auch eine gute Alternative - das hängt von den jeweiligen Projektanforderungen ab.
Ein ausführlicherer Artikel über „Logging in OSGI Enterprise Anwendungen“ ist in Arbeit - ausserdem wird diese Blogserie zum Thema Logging fortgesetzt.
Beispiele mit Sourcecode werden im kommenden Sample meines - Equinox-Riena-Easybeans-Servers zu finden sein, wo das Logging ein wichtiger Aspekt ist.
Ich hoffe, ich habe ein paar Denkanstösse gegeben und kann anderen Projekten etwas helfen, denn aus meiner Erfahrung heraus wird jeder irgendwann mit den Problemen des Logging unter OSGI konfrontiert.
Diskussionen zum Blog bitte in der englischen Version, die sich hier befindet.
...Equinox OSGI Enterprise Anwendungen mit unterschiedlichen Logging-Strategien und Frameworks...