Mit Hilfe von AOP kann ich den Protokollierungscode aus meiner Geschäftslogik entfernen. Aber ich denke, es kann nur verwendet werden, um einfache Dinge zu protokollieren (dh Protokollierungsmethodenein- / -ausgang und Parameterwerte).
Was ist jedoch, wenn ich etwas in meiner Geschäftslogik protokollieren muss? z.B
public void SomeDomainMethod(string id)
{
//Get user by Id
User user = Users.Get(id);
if (user == null)
{
Log.Warn("user is not existed"); //<----------------- Log A
throw new InvalidOperationException("user is not existed");
}
//Step 1
while(true)
{
//do something
}
Log.Info("Step 1 is completed"); //<----------------- Log B
//Step 2
while(true)
{
//do something
}
Log.Info("Step 2 is completed"); //<----------------- Log C
}
Die obige Beispielmethode ist möglicherweise nicht klar genug. Ich möchte hier zeigen, dass die Methode aus Sicht der Domäne als kleinste Einheit behandelt werden sollte. Es sollte nicht in kleinere Stücke geteilt werden.
Ist es möglich, mehr als 3 Protokollierungscodes aus der Methode zu entfernen? Was ist die beste Vorgehensweise für eine solche Situation?
c#
logging
separation-of-concerns
Charlie
quelle
quelle
Antworten:
Sicher!
Nach meiner Erfahrung gibt es jedoch zwei allgemeine Arten der nützlichen Protokollierung:
Alles protokolliert: Protokolle, die über Profiling-APIs erstellt wurden. Gut zum Erkennen von Leistungsproblemen und zum Melden von Ausnahmen. Sehr laut.
Geschäftsereignisprotokolle : In der Geschäftslogik aufgerufene Protokolle. Alles, was das Geschäft interessieren könnte. Minimales Rauschen. Nur bemerkenswerte, logische "geschäftliche" Ereignisse. Gut für Audits und KPIs ...
Daher würde ich zwei Dinge sehr empfehlen. Führen Sie zunächst die Aufgaben anderer Überwachungstools wie New Relic aus und verwenden Sie die .NET-Profilierungs-API 1 . Zweitens protokollieren Sie logische Geschäftsereignisse in Ihrer Geschäftslogik . Das Aufzeichnen bestimmter Ereignisse ist Geschäftslogik.
Und normalerweise würde ich AOP für keine der beiden Protokollierungsarten 2 vorschlagen . Nach meiner Erfahrung möchten Sie entweder alles , was bedeutet, dass Sie einen Profiler verwenden, oder Sie möchten logische / geschäftliche Ereignisse. Und im letzteren Fall ist es meiner Meinung nach einfacher, den Logger einfach in der Geschäftslogik aufzurufen .
1. Aber im Ernst, sparen Sie sich Tausende von Stunden Mühe und verwenden Sie einfach ein vorhandenes Profiler-Tool ...
2. Dies setzt natürlich voraus, dass Sie meine Meinung teilen, dass ein Aspekt kein großartiger Ort ist, um Geschäftsregeln zu verbergen!
quelle
Natürlich können Sie dafür problemlos AOP verwenden. Einfach die Teile umgestalten
in separate Methoden (wie Sie es hätten tun sollen, um Ihren Code sauberer zu machen). Jetzt können Sie Ihr AOP-Framework einfach so konfigurieren, dass die Methodenaufrufe Ihrer Wahl protokolliert werden ( wie hier gezeigt ). Die Ausnahme kann direkt vom Anrufer protokolliert werden, ohne dass AOP verwendet werden muss, um dies aus der Geschäftslogik herauszuholen.
Zu Ihrer Bearbeitung:
Warum sollte es nicht? Wenn Sie in einem "Geschäftslogikkontext" "etwas" protokollieren möchten, das es wert ist, protokolliert zu werden, und wenn diesem "Etwas" ein sinnvoller Name zugewiesen werden kann, ist es in den meisten Fällen sinnvoll, den Code in eine Methode umzugestalten seine eigene. Wenn Sie AOP verwenden möchten, müssen Sie Ihren Code so strukturieren, wie Sie ihn wahrscheinlich hätten strukturieren müssen, unabhängig von den Protokollierungsanforderungen. Sie können dies als Nachteil von AOP oder als Vorteil interpretieren, da Sie ein Feedback erhalten, wo Ihre Codestruktur verbessert werden kann.
quelle
Wenn das Protokollieren nicht Teil der Geschäftsanforderungen ist, ist es, wie Sie sagen, am besten, es vollständig aus Ihrem Code herauszuhalten.
Das bedeutet, dass Sie wirklich keine Dinge wie "Schritt 1 abgeschlossen" protokollieren möchten. Obwohl es anfangs zum Debuggen nützlich sein könnte, wird es in der Produktion nur Gigabyte Müll erzeugen, den Sie nie sehen werden.
Wenn es sich bei Step1Complete um eine Art Geschäftsereignis handelt, für das weitere Maßnahmen erforderlich sind, kann es durch ein gutes altmodisches Ereignis angezeigt werden, ohne dass Sie gezwungen sind, einen ILogger oder ähnliches in Ihre Klasse einzufügen
quelle
Mithilfe eines gängigen Musters können Sie Protokollierungscode aus Ihrer Geschäftslogik ziehen. Möglicherweise lohnt es sich jedoch nicht, dies zu tun
Wenn Sie beispielsweise einen Listener verwenden (Handcraft One oder Event Bus usw.), sieht Ihr Code folgendermaßen aus
Durch die Implementierung der Protokollierung im Listener befindet sich die Protokollierungslogik nicht mehr in Ihrer Geschäftslogik.
Möglicherweise ist dies jedoch nicht immer realistisch, da Sie möglicherweise nicht immer ein aussagekräftiges Ereignis Ihrer Logik definieren können.
Ein anderer Ansatz ist ein Mechanismus wie Dtrace in Solaris, mit dem Sie in laufende Prozesse einbinden können (ich glaube, es gibt Möglichkeiten, ähnliche Aktionen in C # durchzuführen?), Sodass Protokollierung und statistische Erfassungen zur Laufzeit definiert werden können. Es gibt noch andere Nachteile.
quelle
Ein anderer Ansatz besteht darin, die Geschäftsprotokollierung und die technische Protokollierung voneinander zu trennen. Dann können wir die Geschäftsprotokollierung als "Audit" bezeichnen und bestimmte Geschäftsregeln wie Speicherbedingungen und Verarbeitungsregeln wie Business Activity Monitoring anwenden.
Auf der anderen Seite ist die technische Protokollierung oder einfach "Protokollierung" das letzte Mittel, um eine Spur von technischen Problemen zu hinterlassen. Es sollte asynchron, schnell und tolerant sein, wenn die Protokollnachricht nicht beibehalten wird. Außerdem sollten Protokollnachrichten die geringstmögliche Anzahl von Proxys durchlaufen, um nahe an der Ursache des Problems zu sein.
Die Logik der Protokollierung ist sehr variabel und eng mit der Implementierung verbunden. Müssen Sie sie also wirklich vom Code trennen?
Die Logik des Audits sollte als Domänenlogik betrachtet und entsprechend behandelt werden.
In der hexagonalen Architektur gibt es beispielsweise möglicherweise einen Überwachungsport sowie Clients, Speicher und MQ-Ports (und möglicherweise Metriken und Steuerelemente). Dies wäre ein sekundärer Port, dh die Aktivität an diesem Port wird vom Geschäftskern und nicht von externen Systemen ausgelöst.
quelle
Möglichkeiten, um zu vermeiden, dass Sie sich direkt in einer Klasse oder Methode anmelden:
Lösen Sie eine Ausnahme aus und melden Sie sich in einem Catch-Block weiter oben im Aufrufbaum an. Wenn Sie eine Protokollebene erfassen müssen, können Sie eine benutzerdefinierte Ausnahme auslösen.
Rufen Sie Methoden auf, die bereits für die Protokollierung instrumentiert sind.
quelle
Ist es wirklich erforderlich, Ihre Protokollierung von Ihrer Geschäftslogik zu trennen? Die Protokollierung entspricht der geschriebenen Geschäftslogik und ist daher sinnvoll, sich in derselben Klasse / Funktion zu befinden. Noch wichtiger ist, dass die Lesbarkeit des Codes erleichtert wird.
Wenn Sie die Protokollierung jedoch wirklich von Ihrer Geschäftslogik trennen möchten, sollten Sie benutzerdefinierte Ausnahmen auslösen und diese Ausnahmen für die Protokollierung übergeben.
quelle
Nein, nicht in c #
OP, die Antwort auf Ihre spezifische Frage lautet nein, nicht in c #. Es mag andere, nativere AOP-Sprachen geben, aber alle Ansätze für AOP in c #, die ich gesehen habe, können nur aspektierte Verhaltensweisen im Kontext eines Verknüpfungspunkts anwenden , was bedeutet, dass zwischen einem Codeblock und ein Kontrollfluss bestehen muss Ein weiterer. Bestimmte Verhaltensweisen werden nicht in der Mitte einer Methode ausgeführt, außer natürlich durch Aufrufen einer anderen Methode.
Sie können bestimmte Teile der Protokollierung "apsect-ize"
Davon abgesehen könnten Sie bestimmte Bedenken in Bezug auf die Protokollierung beseitigen, nur nicht das Schreiben von Protokollen. Beispielsweise könnte ein Schnittpunkt, der beim Eintritt in eine Methode ausgeführt wird, einen Protokollierungskontext einrichten und alle Eingabeparameter ausgeben, und beim Beenden Ausnahmen auslösen oder ein Protokoll für den permanenten Speicher festschreiben.
Das Schreiben von Protokollen ist sowieso kein Aspekt
Ich würde hinzufügen, dass das Schreiben von Protokollen sowieso kein wirkliches Querschnittsthema ist. Zumindest keine Debug-Protokollierung. Mein Beweis dafür ist, dass Sie keine Querschnittsanforderung schreiben konnten, die vollständig erklärt, was dieser Aspekt bewirken würde - sie ist für jeden Fall spezifisch, da der Zweck des Schreibens des Protokolls darin besteht, zu reflektieren, was mit dem los ist Logik, und die Logik in jeder Methode sollte einigermaßen eindeutig sein (siehe DRY ).
Mit anderen Worten, es gibt eine untrennbare logische Abhängigkeit zwischen dem Schreiben von Protokollen und dem Material, über das geschrieben wird. Sie können es nicht verallgemeinern.
Aber Auditing ist
Wenn Sie eine funktionale Protokollierungsanforderung haben (z. B. eine Überwachungsprotokollierung zur Unterstützung einer Nicht-Ablehnungsanforderung ), würden einige argumentieren (und ich würde zustimmen), dass, wenn Sie feststellen, dass Sie diese Protokollschreibvorgänge mitten in einer Methode ausführen müssen, Sie haben Ihren Code nicht so strukturiert, dass er mit dem aspektorientierten Denken übereinstimmt. In diesem Fall sollten Sie Code in separate Methoden extrahieren, bis Sie die erforderliche Granularität erreicht haben.
quelle