![]() | eigene Logger |
Dieses Kapitel handelt von selbst erstellten Loggern. Über eigene Logger können Sie TreeEvents im Vishnu-Tree nach Ihren Vorstellungen aufbereiten und in eine Log-Datei schreiben.
Wir werden uns nachfolgend zuerst die Logging-Ausgaben des Demo-Projekts LoggerDemo aus der Projektmappe ...\InPlug\TextFileLogger ansehen, danach die Einbindung des TextFileLoggers in das Demo-Programm und zuletzt Auszüge aus der Klasse TextFileLogger.cs.
![]() |
---|
Die Ausgabe des Demo-Programms selbst ist einfach ein Konsole-Fenster, dass Sie mit Enter wieder schließen können (also hier nicht weiter interessant). Allgemeine Informationen über Logger und wie diese in der JobDecription.xml definiert werden können Sie unter Vishnu Akteure nachschlagen. |
Hier zuerst die Logging-Ausgaben des Demo-Projekts:
Der Demo-Job erzeugt zwei Logdateien, eine auf dem Standard-LogPath und eine direkt in einem neuen Unterverzeichnis: ...\TextFileLogger\TextFileLoggerDemo\bin\Debug\sub1\TextFileLoggerDemo.log
2021.07.03 09:41:13,961124 Event: Ereignis auf Standard-LogPath Knoten: ein Knoten|0815, Logical: False, Quelle: 4711 AnyServer, Thread: 0001/08292, Tree: Test-Tree, Status: Done WorkingDirectory: C:\Users\<user>\AppData\Local\Temp\TextFileLoggerDemo\1844
2021.07.03 09:41:14,226374 Event: Ereignis auf speziellem LogPath Knoten: ein Knoten|0815, Logical: False, Quelle: 4711 AnyServer, Thread: 0001/08292, Tree: Test-Tree, Status: Done WorkingDirectory: C:\Users\<user>\AppData\Local\Temp\TextFileLoggerDemo\1844
![]() |
---|
Der Standard-LogPath wird über die Einbindung der
Vishnu.Interchange.dll gesetzt und ist per Voreinstellung Wenn der TextFileLogger später von Vishnu aufgerufen wird, zeigt der Standard-LogPath auf die Vishnu-Logdatei. |
Einbindung und Aufruf der Klasse Logger.cs im Demo-Projekt, siehe folgendes Code-Listing:
using System; using Vishnu.Interchange; namespace TextFileLogger { class Program { static void Main(string[] args) { TextFileLogger myLogger = new TextFileLogger(); myLogger.Log(null, new TreeParameters("Test-Tree", null), new TreeEvent("Ereignis auf Standard-LogPath", "4711", "0815", "ein Knoten", "", false, NodeLogicalState.Done, null, null), null); myLogger.Log(@"sub1\TextFileLoggerDemo.log", new TreeParameters("Test-Tree", null), new TreeEvent("Ereignis auf speziellem LogPath", "4711", "0815", "ein Knoten", "", false, NodeLogicalState.Done, null, null), null); Console.WriteLine("Ende mit Enter"); Console.ReadLine(); } } }
![]() |
---|
Der oben gezeigte Aufruf von Logger im Demo-Projekt dient nur zur Veranschaulichung. Sie selbst müssen den Logger nicht aufrufen, sondern nur in einer JobDescription.xml konfigurieren. Vishnu kümmert sich dann später selbst um den Aufruf. |
Der eigentliche Logger ist in unserem Beispiel die Klasse TextFileLogger.cs, siehe folgendes Code-Listing:
... /// <summary> /// Loggt Vishnu-Ereignisse in ein Logfile. /// </summary> public class TextFileLogger : INodeLogger { /// <summary> /// Übernahme von diversen Logging-Informationen und Ausgabe in eine Logdatei. /// </summary> /// <param name="loggerParameters">Spezifische Aufrufparameter oder null.</param> /// <param name="treeParameters">Für den gesamten Tree gültige Parameter oder null.</param> /// <param name="treeEvent">Objekt mit Informationen über das Ereignis.</param> /// <param name="additionalEventArgs">Enthält z.B. beim Event 'Exception' die zugehörige Exception.</param> public void Log(object loggerParameters, TreeParameters treeParameters, TreeEvent treeEvent, object additionalEventArgs) { // Setzen des Pfades zur Logdatei this.SetLogFilePath(loggerParameters, treeEvent); // Zusammenbauen der zu loggenden Nachricht string bigMessage = BuildLogMessage(treeParameters, treeEvent, additionalEventArgs); this.WriteLog(bigMessage); } ... // Übernimmt entweder einen übergebenen, speziellen Pfad zu einer Logdatei // oder setzt den Default Pfad. Legt ggf. das Zielverzeichnis an. private void SetLogFilePath(object loggerParameters, TreeEvent treeEvent) { if (loggerParameters != null) { this._debugFile = loggerParameters.ToString(); } else { this._debugFile = treeEvent.ReplaceWildcards("%DebugFile%"); } if (!Directory.Exists(Path.GetDirectoryName(this._debugFile))) { Directory.CreateDirectory(Path.GetDirectoryName(this._debugFile)); } } // Baut aus den übergebenen Parametern einen einzigen formatierten string zusammen. private string BuildLogMessage(TreeParameters treeParameters, TreeEvent treeEvent, object additionalEventArgs) { string indent = " "; string addInfos = indent; if (treeEvent.Name.Contains("Exception")) { addInfos += (additionalEventArgs as Exception).Message; } if (treeEvent.Name.Contains("ProgressChanged")) { addInfos += String.Format("Fortschritt {0:d3}%", Convert.ToInt32(additionalEventArgs)); } string timestamp = System.String.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:yyyy.MM.dd HH:mm:ss,ffffff}", new object[] { treeEvent.Timestamp }); StringBuilder bigMessage = new StringBuilder(timestamp + " Event: " + treeEvent.Name); string IdName = treeEvent.NodeName + "|" + treeEvent.SenderId; bigMessage.Append(Environment.NewLine + indent + "Knoten: " + IdName); bigMessage.Append(", Logical: " + treeEvent.Logical); bigMessage.Append(", Quelle: " + treeEvent.SourceId); bigMessage.Append(Environment.NewLine + indent + treeEvent.ReplaceWildcards("%MachineName%") + ", Thread: " + treeEvent.ThreadId.ToString()); bigMessage.Append(", Tree: " + treeParameters.ToString()); if (addInfos.Trim() != "") { bigMessage.Append(Environment.NewLine + addInfos); } if (!String.IsNullOrEmpty(treeEvent.NodePath)) { bigMessage.Append(Environment.NewLine + indent + treeEvent.NodePath); } bigMessage.Append(", Status: " + treeEvent.State.ToString()); bigMessage.Append(Environment.NewLine + indent + "WorkingDirectory: " + treeEvent.ReplaceWildcards("%WorkingDirectory%")); return bigMessage.ToString(); } // Die Routine versucht, in eine möglicherweise von mehreren Knoten gleichzeitig // genutzte Logdatei zu schreiben; wirft im Fehlerfall keine Exception, sondern // versucht es wieder, bis ein Zähler abgelaufen ist. // Im ungünstigsten Fall kann der Logging-Versuch fehlschlagen. private void WriteLog(string message) { int maxTries = 5; StreamWriter streamWriter; int i = 0; do { try { using (streamWriter = new StreamWriter(new FileStream(this._debugFile, FileMode.Append, FileAccess.Write), Encoding.Default)) { streamWriter.WriteLine(message); i = maxTries; // erfolgreich, Loop beenden } } catch (SystemException) { Thread.Sleep(10); // 10 tausendstel Sekunden warten } } while (++i < maxTries); } ...
Die Klasse TextFileLogger implementiert die von Vishnu bereitgestellte Schnittstelle Vishnu.InterchangeINodeLogger. Die einzige Routine Log(...) übernimmt den Pfad zur Logdatei (Unterroutine SetLogFilePath), baut aus den übergebenen Parametern einen zusammenhängenden Meldungstext (Unterroutine BuildLogMessage) und ruft zuletzt die interne Routine WriteLog auf, in der versucht wird, die Meldung in die Logdatei zu schreiben.
![]() |
---|
Da bei der späteren Verwendung in Vishnu unter Umständen mehrere Logger gleichzeitig versuchen, in dieselbe Logdatei zu schreiben, kann es dazu kommen, dass ein oder mehrere Schreibversuche schiefgehen. Diese Logger-Implementierung versucht es deshalb insgesamt fünfmal, bevor (ohne weitere Fehlermeldung) aufgegeben wird. |