div class=“articleAbstract“>
Entwicklerteams, die Logging schon zur Entwicklungszeit ausgiebig nutzen, haben es sehr leicht Fehler in der laufenden Produktionsumgebung zu analysieren. Man muss nur kurz den Loglevel hochsetzen, wenn – ja wenn – man Zugriff auf die Konfigurationsdatei hat. In großen Produktionsumgebungen ist dies üblicherweise nicht erlaubt.
Mit ein bisschen Programmierung kann man die Loglevels für log4net im laufenden Betrieb auf einer Admin-Seite anzeigen und ein- bzw. ausschalten (toggeln). Ein exemplarisches Userinterface – hier als ASP.NET User Control realisiert – sieht im Ergebnis wie folgt aus:
Funktionsweise (Business Logic)
LogLevels
In log4net kann ein Logger genau einen Level haben. In der obigen Grafik zum Userinterface ist der Level für den Logger “MyApp.Log1” auf “Error” gesetzt. Dadurch ergibt sich automatisch, dass die Level “Info” und “Debug” deaktiviert und “Fatal” aktiviert sind.
- Aktivieren: Wird ein Level von deaktiviert in aktiviert geändert, so wird der Level direkt am Logger gesetzt. Beispiel: Klicken von “IsDebug” des Loggers “MyApp.Log1” setzt den Level “Debug” des Loggers.
- Deaktivieren: Wird ein Level deaktiviert, so wird der nächste höhere Level aktiviert. Beispiel: Klicken auf “IsError” des Loggers “MyApp.Log1” setzt den Level des Loggers auf “Fatal”.
Somit kann jede gewünschte Logging-Stufe direkt ein- und ausgeschaltet werden.
Defining Logger
Mit dem Interface ILog der Logger können die Informationen zu IsFatal, IsError etc. ermittelt werden. Theoretisch kann für jeden Logger ein eigener LogLevel definiert werden. In der Praxis wird man sich jedoch darauf beschränken den Level nur für den Root-Logger oder wenige andere anwendungsrelevante Logger zu setzen, deren Werte sich auf alle Kinder vererben. Die Vererbung wird im Userinterface in der Spalte “Defining Logger” angezeigt. Beispiel: Wird der Level für “MyApp.Log1.Sub11” geändert, so ändert sich auch der geerbte Wert für den Logger “MyApp.Log1.Sub11.Sub111”
Code
Der Code besteht aus zwei Methoden. Die erste Methode GetLoggerInformation() ermittelt den Zustand aller Logger. Die zweite Methode ToggleLogLevel() schaltet den Zustand eines LogLevels anhand der vorgestellten Business Logic um.
1: namespace Sdx.Logging
2: {
3: using log4net;
4: using log4net.Core;
5: using System.Linq;
6: using System.Collections.Generic;
7:
8: /// <summary>
9: /// Helper class, to retrieve all loggers and toggle levels
10: /// </summary>
11: public class LogLevelToggler
12: {
13: /// <summary>
14: /// Retrieve current Logger information
15: /// </summary>
16: /// <returns></returns>
17: public List<LoggerInformation> GetLoggerInformation()
18: {
19: var result = new List<LoggerInformation>();
20:
21: // if you like to care about repositories, feel free to modify
22: // get ILog interfaces of all loggers
23: foreach (var repository in LogManager.GetAllRepositories())
24: {
25: var loggers = repository.GetCurrentLoggers();
26: foreach (var l in loggers)
27: {
28: // Add Logging information
29: var li = new LoggerInformation
30: {
31: Name = l.Name,
32: Repository = repository.Name,
33: IsFatal = l.IsEnabledFor(Level.Fatal),
34: IsError = l.IsEnabledFor(Level.Error),
35: IsInfo = l.IsEnabledFor(Level.Info),
36: IsDebug = l.IsEnabledFor(Level.Debug),
37: };
38: result.Add(li);
39:
40: // enrich hierarchie information
41: var hierarchieLogger = l as log4net.Repository.Hierarchy.Logger;
42: if (hierarchieLogger != null)
43: {
44: // get defining logger for level
45: while (hierarchieLogger.Level == null && hierarchieLogger.Parent != null)
46: {
47: hierarchieLogger = hierarchieLogger.Parent;
48: }
49: li.DefiningLogger = hierarchieLogger.Name;
50: }
51: else
52: {
53: // fallback
54: li.DefiningLogger = "-- unknown --";
55: }
56: }
57: }
58: return result;
59: }
60:
61: /// <summary>
62: /// Supported Levels
63: /// </summary>
64: public static readonly Dictionary<string, Level> LevelMap = new Dictionary<string, Level>
65: {
66: {"IsOff", Level.Off },
67: {"IsFatal", Level.Fatal},
68: {"IsError", Level.Error},
69: {"IsInfo", Level.Info},
70: {"IsDebug", Level.Debug},
71: {"IsAll", Level.All},
72: };
73:
74:
75: /// <summary>
76: /// Toggle level for logger
77: /// </summary>
78: /// <param name="loggerName">name of logger</param>
79: /// <param name="selectedLevel">level to toggle</param>
80: public void ToggleLogLevel(string loggerName, Level selectedLevel)
81: {
82: // get Logger interface
83: var logger = log4net.LogManager.GetLogger(loggerName);
84: if (logger != null)
85: {
86: // get hierachical logger
87: var hl = logger.Logger as log4net.Repository.Hierarchy.Logger;
88: if (hl != null)
89: {
90: if (hl.EffectiveLevel <= selectedLevel)
91: {
92:
93: // Disable Selected Level by selecting Level + 1
94: // eg. disable INFO by setting level to ERROR
95: hl.Level = LogLevelToggler.LevelMap.TakeWhile(l => l.Value != selectedLevel).Last().Value;
96: }
97: else
98: {
99: // Enable Selected Level
100: hl.Level = selectedLevel;
101: }
102: }
103: }
104: }
105: }
106: }
Business Logic: LogLevelToggler
1: namespace Sdx.Logging
2: {
3: /// <summary>
4: /// Display object
5: /// </summary>
6: public class LoggerInformation
7: {
8: // Name of Logger
9: public string Name { get; set; }
10: public string Repository { get; set; }
11:
12: // Levels
13: public bool IsFatal { get; set; }
14: public bool IsError { get; set; }
15: public bool IsInfo { get; set; }
16: public bool IsDebug { get; set; }
17:
18: // Name of logger, defining the Level
19: public string DefiningLogger { get; set; }
20: }
21: }
Value Object: LoggerInformation
Ausblick
Das zugehörige ASP.NET Control zum bequemen Einbinden in eigene Projekte habe ich im folgenden Beitrag veröffentlicht. Eine Einbindung in eine Admin-Seite (!) ist dann schnell durchgeführt. Viel Spaß mit dem kleinen Helferlein.
Sie sehen gerade einen Platzhalterinhalt von Facebook. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von Instagram. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von X. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr Informationen