Tipps zur ULS-Protokollierung
Tipps zur ULS-Protokollierung
UPDATE 04.02.2011: Ich empfehle, in diesem Zusammenhang einen Blick auf das aktualisierte Beispiel unter https://blogs.msdn.com/b/sharepoint_de/archive/2011/03/21/tipps-zur-uls-protokollierung-teil-160-2.aspx zu werfen. Das neue Beispiel ist besser und funktionaler.
Als ich kürzlich einem Projekt die ULS-Protokollierung hinzufügte, bemerkte ich einen nervigen Nebeneffekt. In den ULS-Protokollen wurde der Bereich (Area) als unbekannt (Unknown) angezeigt. Mir ist bewusst, dass einige Aspekte dieses Problems schon anderweitig behandelt wurden. Ich wollte lediglich schnell einen Blogbeitrag schreiben, in dem ich beschreibe, wie dieses Problem am schnellsten behoben werden kann (auf jeden Fall unkomplizierter als dies bei einigen anderen beschriebenen Lösungen der Fall ist). Es soll darauf hingewiesen werden, dass meiner Meinung nach mit dem vom Best Practices-Team auf CodePlex verfügbar gemachte „Logging Framework“ diese Schritte automatisch ausgeführt werden, falls Sie sich nicht damit abmühen möchten. Ich schreibe jedoch gewöhnlich so weit wie möglich meinen eigenen Code, weshalb ich die Lösung an dieser Stelle kurz beschreiben werde.
Zunächst soll darauf hingewiesen werden, dass in der SDK-Dokumentation weitgehend vom Erstellen einer neuen SPDiagnosticsCategory-Kategorie die Rede ist. Mit dem Konstruktor für eine neue Instanz der Klasse können Sie den Namen der Kategorie angeben. In diesem Fall wird definitiv in der Spalte Category (Kategorie) des ULS-Protokolls jeder gewünschte benutzerdefinierte Kategoriename angezeigt. In den meisten Fällen werden Sie für Ihre benutzerdefinierte Protokollierung auch einen benutzerdefinierten Bereich (Area) für die benutzerdefinierte Kategorie (Category) verwenden möchten. Dies ist im SDK leider wesentlich komplizierter, da es nicht möglich ist, mit einem einfachen Konstruktor einen neuen Bereich (Area) zu erstellen und zu verwenden. Sie müssen vielmehr eine eigene Klasse erstellen, die von SPDiagnosticsServiceBase abgeleitet ist.
Für die Implementierung haben Sie sich dafür entschieden, eine einzelne CS-Datei zu erstellen, die sowohl die Protokollierungsklasse als auch die Basisklasse für den Diagnosedienst enthält. Zunächst werde ich mit der Basisklasse für den Diagnosedienst beginnen (im Folgenden habe ich die gesamte Klasse eingefügt). Anschließend werde ich auf einige wichtige Punkte hinweisen:
public class SteveDiagnosticService : SPDiagnosticsServiceBase
{
private const string LOG_AREA = "Steve Area";
public enum LogCategories
{
SteveCategory
}
public SteveDiagnosticService()
: base("Steve Diagnostics Service", SPFarm.Local)
{
}
public SteveDiagnosticService(string name, SPFarm parent)
: base(name, parent)
{
}
protected override bool HasAdditionalUpdateAccess()
{
return true;
}
public static SteveDiagnosticService Local
{
get
{
return SPDiagnosticsServiceBase.GetLocal<SteveDiagnosticService>();
}
}
public void LogMessage(ushort id, LogCategories LogCategory, TraceSeverity traceSeverity,
string message, params object[] data)
{
if (traceSeverity != TraceSeverity.None)
{
SPDiagnosticsCategory category
= Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];
Local.WriteTrace(id, category, traceSeverity, message, data);
}
}
protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
{
List<SPDiagnosticsCategory> categories = new List<SPDiagnosticsCategory>();
categories.Add(new SPDiagnosticsCategory(
LogCategories.SteveCategory.ToString(),
TraceSeverity.Medium, EventSeverity.Information));
SPDiagnosticsArea area = new SPDiagnosticsArea(
LOG_AREA, 0, 0, false, categories);
List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>();
areas.Add(area);
return areas;
}
}
Betrachten wir nun die interessanten Komponenten:
private const string LOG_AREA = "Steve Area";
Hier definiere ich den Namen für den Bereich (Area), der in das ULS-Protokoll geschrieben wird.
public enum LogCategories
{
SteveCategory
}
Dies ist die Liste der Kategorien, die ich meinem benutzerdefinierten Bereich (Area) hinzufügen werde. In diesem Fall werde ich nur eine Kategorie für diesen Bereich (Area) verwenden. Wenn Sie allerdings mehrere Kategorien wünschen, müssen Sie nur den Inhalt dieser Enumeration erweitern.
public void LogMessage(ushort id, LogCategories LogCategory, TraceSeverity traceSeverity,
string message, params object[] data)
{
if (traceSeverity != TraceSeverity.None)
{
SPDiagnosticsCategory category
= Local.Areas[LOG_AREA].Categories[LogCategory.ToString()];
Local.WriteTrace(id, category, traceSeverity, message, data);
}
}
Dies ist eine der beiden wichtigen zu implementierenden Methoden, mit denen in das ULS-Protokoll geschrieben wird. In der ersten Zeile wird die SPDiagnosticsCategory-Kategorie abgerufen, und außerdem wird dabei auf den zugehörigen Bereich (Area) verwiesen. In der zweiten Zeile wird die Basisklassenmethode für die lokale SPDiagnosticsServiceBase-Klasse aufgerufen, die in das ULS-Protokoll geschrieben werden soll. In diesem Zusammenhang übergebe ich die Kategorie (Category), die meinem Bereich (Area) zugeordnet ist.
protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
{
List<SPDiagnosticsCategory> theCategories = new List<SPDiagnosticsCategory>();
theCategories.Add(new SPDiagnosticsCategory(
LogCategories.SteveCategory.ToString(),
TraceSeverity.Medium, EventSeverity.Information));
SPDiagnosticsArea theArea = new SPDiagnosticsArea(
LOG_AREA, 0, 0, false, theCategories);
List<SPDiagnosticsArea> theArea = new List<SPDiagnosticsArea>();
theArea.Add(area);
return theArea;
}
Bei dieser Überschreibung gebe ich alle meine benutzerdefinierten Bereiche an SharePoint zurück. In diesem Fall werde ich nur einen einzelnen Bereich (Area) verwenden, weshalb ich nur diesen Bereich zurücksende. Darüber hinaus verwende ich, wie bereits weiter oben erwähnt, nur eine benutzerdefinierte Kategorie (Category) für meinen Bereich (Area). Wenn ich mehrere benutzerdefinierte Kategorien verwenden möchte, würde ich 1) sie der weiter oben beschriebenen Enumeration hinzufügen und 2) jede Kategorie meiner in dieser Methode definierten Liste theCategories hinzufügen.
Das ist also das ganze Zauberwerk beim Hinzufügen eines benutzerdefinierten Bereichs und beim Anzeigen des benutzerdefinierten Bereichs in der entsprechenden Spalte der ULS-Protokolle. Die Implementierung der Protokollierungsklasse ist ebenfalls ziemlich einfach. Ich habe hier den Hauptteil eingefügt, den ich dann erläutern werden:
public class Log
{
private const int LOG_ID = 11100;
public static void WriteLog(string Message, TraceSeverity TraceLogSeverity)
{
try
{
//in this simple example, I’m always using the same category
//you could of course pass that in as a method parameter too
//and use it when you call SteveDiagnosticService
SteveDiagnosticService.Local.LogMessage(LOG_ID,
SteveDiagnosticService.LogCategories.SteveCategory,
TraceLogSeverity, Message, null);
}
catch (Exception writeEx)
{
//ignore
Debug.WriteLine(writeEx.Message);
}
}
}
Dieser Code lässt sich mit meinen Methoden ziemlich einfach implementieren. Da WriteLog eine statische Methode ist, lautet der Code beispielsweise Log.WriteLog(“This is my error message”, TraceSeverity.Medium); . In diesem Beispiel wird im ULS-Protokoll ein Eintrag im Bereich (Area) „Steve Area“ und in der Kategorie (Category) „SteveCategory“ mit der Meldung „This is my error message“ erstellt.
Es handelt sich hierbei um einen übersetzten Blogbeitrag. Sie finden den Originalartikel unter Tips for ULS Logging .