Hallo,
ich stehe gerade vor folgendem Problem:
Ich habe eine statische Klasse Logger, mit deren Hilfe ich mein LogFile erzeugen will.
Dazu biete ich drei Methoden an, für Warnings, Errors und Messages.
Beispiel:
public static void WriteMessage(object sender, message)
{
...
}
Mein Wunsch wäre es jetzt über den sender mitzuteilen, in welcher Methode (Namespace und Class) WriteMessage aufgerufen wurde. Doch nur wie...
StackTrace habe ich schon verwendet, doch leider liefert der nicht immer was anständiges zurück (z.B. bei einem Konstruktor) und leider bekomme ich damit die Klasse und den Namespace nicht raus.
Daher meine Frage wie bekomme ich diese Informationen (ich will dies nicht über "strings" lösen, also einfach per drei strings die Informationen übergeben)
Vielen Dank schon mal und viele Grüße
Quaneu
Hallo Quaneu,
mit StackTrace funktionierts auch:
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
foreach (StackFrame sf in stackFrames)
{
Debug.WriteLine(sf.GetMethod().Name); //Methodenname
Debug.WriteLine(sf.GetMethod().DeclaringType.Name); //Klassenname
Debug.WriteLine(sf.GetMethod().DeclaringType.Namespace); //Namespace
Debug.WriteLine(sf.GetMethod().DeclaringType.AssemblyQualifiedName); //Kompletten Pfad zur Klasse
}
Gruß
Michael
Unabhängig davon, dass ich keine Lösung weis, da es gegen OOP verstoßen würde ein kleiner Tipp:
Dazu biete ich drei Methoden an, für Warnings, Errors und Messages.
Biete eine Methode an, die einen Status als Enum annimmt (Warning, Errors, Messages).
So vereinfachst du zum einen die Verwendung und zum anderen hast du eine Zentrale Log-Schnittstelle.
Was du intern dann machst bleibt dir überlassen.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
@xxMUROxx:
Dies klappt soweit ganz gut, Danke dir. Doch leider wird eben bei einem Konstruktor immer der Methodenname ".ctor" angezeigt. Aber den bekomme ich ja dann über den KlassenNamen. Daher wäre dies eine Lösung. Vielen Dank dafür.
@inflames2k:
Vielen Dank für deinen Hinweis, habe diesen gerade umgesetzt. Wie würdest Du denn soetwas realisieren? Ich denke Du störst dich an der static class. Doch ich habe diesen Weg gewählt, da es eine zentrale Stelle geben soll, an der "geschrieben" werden kann.
So vereinfachst du zum einen die Verwendung und zum anderen hast du eine Zentrale Log-Schnittstelle.
Das sehe ich anders:
Das Verhalten einer Methode sollte nicht von einer compiletime-Konstante abhängen - da sind mehrere Methoden IMHO durchaus die elegantere Variante.
Intern können sie ja trotzdem eine Methode aufrufen.
Zum Zugreifen auf den StackTrace: So lange das zu Logging/Debugging-Zwecken geschieht, kann ich nichts "Unsauberes" daran erkennen - lediglich den Programmablauf sollte man nicht vom Stack abhängig machen.
Mein Logger arbeitet auch als Static. - Aber eben mit einem ENUM. Kannst ja mal anschauen. (Siehe Signatur).
Ich biete sogar nur eine Klasse an über die alles passiert (die statisch ist) und intern anhand der Konfiguration Xml-Logfile oder Windows EventLog nutzt. -> Aufrufende Methoden logge ich allerdings nicht.
@winSharp93
Naja, das ist wohl Ansichtssache.
Aber wenn ich sowieso einen Log-Eintrag schreibe, wo sich nur der Typ unterscheidet, kann ich das doch anhand des ENUM machen. - Ist jedenfalls meine Auffassung.
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
Naja, das ist wohl Ansichtssache.
Ja - durchaus.
Aber wenn ich sowieso einen Log-Eintrag schreibe, wo sich nur der Typ unterscheidet, kann ich das doch anhand des ENUM machen
Die Frage ist jedoch: Was bringt ein Enum für Vorteile im Vergleich zu einer Methode aus Aufrufersicht?
IMHO sind das kaum welche bis gar keine.
Stattdessen wird die Methode komplexer: Ein weiterer Parameter erhöht die Unübersichtlichkeit, muss validiert werden und dann in der Methode erneut geprüft.
Auch aus Aufrufersicht wird die Methode komplexer:
Logger.Log(Severity.Warning, "Person {0} not found", person.Id);
//vs:
Logger.Warning("Person {0} not found", person.Id);
Letzteres Variante ist nicht nur kürzer, es ist auch deutlich besser zu erkennen, was genau geloggt wird.
Zudem ist man besser gewappnet für zukünftige Refactorings: Angenommen, _Error_s sollen zusätzlich um einen optionalen Fehlercode erweitert werden; bei Informationsmeldungen soll dieser jedoch nicht zum Zuge kommen.
In diesem Fall würde es reichen, nur die Error-Methode zu verändern, da sie genau eine Zuständigkeit hat.
Weiteres Beispiel:
Auch im Framework existieren an vielen Stellen verschiedennamige Methoden, die man theoretisch auch zu einer zusammenfassen könnte.
So schreibt man beispielsweise:
s.ToLower();
s.ToLowerInvariant();
//und nicht:
s.ToLower(false);
s.ToLower(true);
//oder:
enumerable.OrderBy(p => p.Name);
enumerable.OrderByDescending(p => p.Name);
//Statt:
enumerable.OrderBy(SortOrder.Ascending, p => p.Name);
enumerable.OrderBy(SortOrder.Descending, p => p.Name);
Und nochetwas, wer statische Klassen fürs logging benutzt verwehrt sich einen Umstieg und sollte sich auch mal überlegen etwas zu Architektur zu lesen.
Das benutzen eine IOC Containers ist wirklich nicht schwer und vereinfacht solche sachen echt ungemein.
Naja...wenn man es erst einmal verstanden hat ist es wirklich einfach, aber ggf. dauert es ein bißchen **bis **man es wirklich verstanden hat... 😁 Siehe DI/IoC in der Praxis (und korrekter Aufbau der zugehörigen Klassen)
Mich würde aber sehr interessieren wie Du Logging in Verbindung mit IoC benutzt.
Klar, ich kann mir den Logger injecten lassen, aber dann habe ich ja in **jeder **Klasse die irgendwas loggen muß den ILogger im Konstruktor.
Es gibt auch container, die das injecten über eine property zulassen, und das zumeist auch lazy, d.h. erst wenn du es brauchst. Um irgendeine Referenz auf dein Logging interface wirst du aber nicht herum kommen.
Die Hinweise, dass und wie man statische Klassen beim Logging vermeiden kann, sind jetzt ausreichend gegeben worden. Bitte nicht mehr tiefer einsteigen. Das eigentliche Thema ist ein anderes, s. Titel.