-
log4net Integration für ActiveEntry
Veröffentlicht am 01. August, 2011 in den Kategorien ClipboardDie hier enthaltene Beschreibung basiert auf ActiveEntry 4.1, sollte aber auch in neueren Versionen (inkl. Quest One Identity Manager) funktionieren. Eine Garantie dafür kann selbstverständlich nicht übernommen werden. Alle Änderungen erfolgen auf eigene Verantwortung.
Was wollen wir?
Standardmäßig wird von jedem ActiveEntry Dienst eine (lokale) Log-Datei erstellt. Dafür wird ein so genannter JobLogger verwendet. ActiveEntry unterstützt verschiedene JobLogger und bringt je nach Version auch andere mit (z.B. zum Schreiben ins Windows Event-Log). Auf Basis dieser Schnittstelle kann man auch einen eigenen JobLogger erstellen – genau dies wollen wir machen, um alle von log4net unterstützen Ziele (Appender) nutzen zu können.
Was müssen wir dafür tun?
- Eine aktuelle log4net Version herunterladen
- Ein neues Visual Studio Projekt für eine Klassenbibliothek erstellen (CLR 2.0) und
- neben der Referenz zur log4net.dll einen Verweise auf die JobService.dll (aus dem ActiveEntry Verzeichnis) hinzufügen.
- Eine neue Klasse anlegen und von VI.JobService.Logging.JobLoggerBase ableiten.
- Mindestens die Methode LogFiltered überschreiben um die Meldungen an log4net weiterzugeben:
protected override void LogFiltered(ILogEntry entry) { var log = log4net.LogManager.GetLogger("ActiveEntry"); var logData = new LoggingEventData(); switch (entry.Severity) { case VI.Base.MsgSeverity.Info: switch (entry.EntryType) { case LogEntryType.Message: logData.Level = Level.Debug; break; default: logData.Level = Level.Info; break; } break; case VI.Base.MsgSeverity.Warning: logData.Level = Level.Warn; break; default: logData.Level = entry.EntryType == LogEntryType.Result ? Level.Info : Level.Error; break; } logData.LoggerName = String.Format("ActiveEntry.{0}", base.ID); logData.Domain = entry.ThreadName; logData.Message = String.Format("[{0}] {1}", entry.EntryType, entry.Message); logData.TimeStamp = entry.Time; log.Logger.Log(new log4net.Core.LoggingEvent(logData)); } - log4net Konfiguration festlegen – wir machen das in einer externen Datei (IdmLog.xml) damit wir die gleiche Konfiguration auch an anderer Stelle verwenden können:
<log4net> <appender name="UdpAppender" type="log4net.Appender.UdpAppender"> <localPort value="7777" /> <remoteAddress value="localhost" /> <remotePort value="8080" /> <layout type="log4net.Layout.XmlLayoutSchemaLog4j, log4net" /> </appender> <!-- Set root logger level to DEBUG and its only appender to UdpAppender--> <root> <level value="DEBUG" /> <appender-ref ref="UdpAppender" /> </root> </log4net>
- Konfiguration einbinden – am besten über ein Assembly-Attribut (z.B. in AssemblyInfo.cs):
[assembly: log4net.Config.XmlConfigurator(ConfigFile="IdmLog.xml", Watch=true)]
- Alles kompilieren und das Ergebnis (unsere neue DLL, die log4net.dll zusammen mit log4net.xml und der Konfigurationsdatei) mit dem SoftwareLoader in die Datenbank packen.
- Nun müssen wir nur noch die JobService-Konfiguration ergänzen. In der Datei JobService.cfg gibt es eine Kategorie namens jobloggers. Hier müssen wir unseren neuen JobLogger einfügen:
<category name="jobloggers"> <value name="filelogwriter">VI.JobService.FileLogWriter,JobService</value> <value name="log4net">SC.Idm.Logging.Log4NetWriter,SC.Idm.Logging</value> </category>Wichtig: Der Wert des log4net Elements muss den vollqualifizierten Namen unserer JobLogger Klasse und den Namen des Assemlies (der neuen DLL) enthalten (case sensitive!)
- Dienst neu starten und Testen
Wenn das ganze funktioniert, kann die Konfiguration für alle Server angepasst werden. Änderungen an der log4net-Konfigurationsdatei in der Datenbank (mittels SoftwareLoader) werden automatisch an alle Server verteilt.
Was fangen wir damit an?
Um die Auswertung zu vereinfachen kann man alle Log-Meldungen z.B. in eine Datenbanktabelle schreiben. Dies bietet den großen Vorteil einer zentralen Anlaufstelle, kann bei vielen Applikationsservern aber auch zu einen Flaschenhals führen. Da auch die Datenmenge entsprechend hoch sein kann, sollte diese Tabelle am besten in einer eigenen Datenbank (oder sogar auf einem eigenen Server) liegen und über geeignete Inidzes verfügen. Des weiteren kann die Datenmenge natürlich auch über die log4net Konfiguration beliebig eingeschränkt werden.
Hat man aber erstmal alle Meldungen in einer zentralen Datenbank, kann man mit beliebigen Abfragetools diverse Auswertungen erstellen (neben wilden Statistiken können die gesammelten Daten auch direkt gefiltert und angezeigt werden – besonders zum Testen/Bugfixing hilfreich). Wir verwenden dazu ein selbsterstelltes kleines Tool – zu dem wird es demnächst hier einen eigenen Beitrag geben.
Wenn man alle Daten in eine Datenbank schreibt, sollte man darüber Nachdenken (ähnlich wie bei der JobHistory) alte Einträge irgendwann auch wieder zu entfernen.
Was gibt es sonst noch?
In eigenen Skripten kann man sich entscheiden, ob man über die VI-Standardmethoden ebenfalls ins Log-Schreibt (Meldung landet dann bei allen für den Service konfigurierten JobLoggern), oder direkt log4net verwendet. Bei log4net wird die Meldung zwar nicht über die anderen JobLogger, sondern “nur” über die konfigurierten Logger/Appender geschickt, aber dafür enthält die Meldung auch deutlich mehr Kontextinformationen (Logger, Klasse usw.). Wir favorisieren auf jeden Fall die zweite Varante.
Geschrieben von Andreas Schauerte