Mehrschichtige Architektur: Wo sollte ich die Fehlerprotokollierung \ Behandlung implementieren?

17

Ich überarbeite derzeit ein großes Subsystem mit einer mehrschichtigen Architektur und habe Mühe, eine wirksame Strategie für die Fehlerprotokollierung und -behandlung zu entwickeln.

Angenommen, meine Architektur besteht aus den folgenden drei Ebenen:

  • Öffentliche Schnittstelle (IE und MVC-Controller)
  • Domänenschicht
  • Datenzugriffsschicht

Meine Verwirrung ist, wo ich die Fehlerprotokollierung implementieren soll:

  1. Die einfachste Lösung wäre, die Protokollierung auf der obersten Ebene zu implementieren (IE, Public Interface \ MVC Controller). Dies fühlt sich jedoch falsch an, da es bedeutet, die Ausnahme durch die verschiedenen Ebenen zu sprudeln und sie dann aufzuzeichnen. anstatt die Ausnahme an der Quelle zu protokollieren.

  2. Es ist offensichtlich die beste Lösung, die Ausnahme an der Quelle zu protokollieren, da ich die meisten Informationen habe. Mein Problem dabei ist, dass ich nicht jede Ausnahme an der Quelle abfangen kann, ohne ALLE Ausnahmen abzufangen. Auf der Ebene der Domäne / öffentlichen Schnittstelle führt dies dazu, dass Ausnahmen abgefangen werden, die von der darunter liegenden Ebene bereits abgefangen, protokolliert und erneut ausgelöst wurden .

  3. Eine andere mögliche Strategie ist eine Mischung aus # 1 und # 2; Dabei fange ich bestimmte Ausnahmen auf der Ebene ab, auf der sie höchstwahrscheinlich ausgelöst werden (IE-Catching, Protokollierung und erneutes Auslösen SqlExceptionsauf der Datenzugriffsebene), und protokolliere dann alle weiteren nicht erfassten Ausnahmen auf der obersten Ebene. Dies würde jedoch auch erfordern, dass ich jede Ausnahme auf oberster Ebene abfange und erneut protokolliere, da ich nicht zwischen Fehlern, die bereits protokolliert wurden, und Fehlern, die noch nicht behandelt wurden, unterscheiden kann.

Dies ist offensichtlich ein Problem in den meisten Softwareanwendungen. Daher muss es eine Standardlösung für dieses Problem geben, die dazu führt, dass Ausnahmen an der Quelle abgefangen und einmal protokolliert werden. Ich kann jedoch nicht sehen, wie ich das selbst machen soll.

Beachten Sie, dass der Titel dieser Frage " Ausnahmen in einer mehrschichtigen Anwendung protokollieren" sehr ähnlich ist , die Antworten in diesem Beitrag jedoch nicht detailliert genug sind, um meine Frage zu beantworten.

KidCode
quelle
1
Ein Ansatz, den ich manchmal verwende, besteht darin, eine eigene Exception- (oder RuntimeException-) Unterklasse zu erstellen und diese auszulösen, einschließlich der ursprünglichen Ausnahme als verschachtelte Ausnahme. Natürlich bedeutet dies, dass ich beim Erfassen von Ausnahmen auf einer höheren Ebene den Typ der Ausnahme überprüfen muss (meine eigenen Ausnahmen werden nur erneut ausgelöst, andere Ausnahmen werden protokolliert und in neue Instanzen meiner Ausnahmen aufgenommen). Aber ich arbeite schon lange alleine, daher kann ich keinen "offiziellen" Rat geben.
SJuan76
4
The easiest solution would be to implement the logging at the top level- mach das. Das Protokollieren von Ausnahmen an ihrer Quelle ist keine gute Idee, und jede Anwendung, auf die ich gestoßen bin, die dies tut, war ein PITA zum Debuggen. Es sollte in der Verantwortung des Anrufers liegen, Ausnahmen zu behandeln.
Justin
Sie scheinen eine bestimmte Implementierungstechnik / Sprache im Auge zu haben, andernfalls ist Ihre Aussage "Ausnahmen, die protokolliert wurden, nicht von denen zu unterscheiden, die nicht protokolliert wurden" schwer zu verstehen. Können Sie mehr Kontext geben?
Vroomfondel
@Vroomfondel - Du hast recht. Ich verwende C # und das Umbrechen des Codes in jede Ebene mit try{ ... } catch(Exception ex) { Log(ex); }würde dazu führen, dass auf jeder Ebene dieselbe Ausnahme protokolliert wird. (Es scheint auch eine ziemlich schlechte Praxis zu sein, jede Ausnahme auf jeder Ebene der Codebasis
abzufangen

Antworten:

18

Zu Ihren Fragen:

Die einfachste Lösung wäre, die Protokollierung auf der obersten Ebene zu implementieren

Es ist absolut richtig und plausibel, die Ausnahmeblase bis zur obersten Ebene zu haben. Keine der Methoden der höheren Ebene versucht, einen Prozess nach dem Fehler fortzusetzen, was normalerweise nicht gelingen kann. Und eine gut ausgestattete Ausnahme enthält alle Informationen, die für die Protokollierung erforderlich sind. Wenn Sie nichts gegen Ausnahmen unternehmen, können Sie Ihren Code sauber halten und sich auf die Hauptaufgabe konzentrieren, anstatt auf die Fehler.

Es ist offensichtlich die beste Lösung, die Ausnahme an der Quelle zu protokollieren, da ich die meisten Informationen habe.

Das ist zur Hälfte richtig. Ja, die nützlichsten Informationen sind dort verfügbar. Aber ich würde empfehlen, all dies in das Exception-Objekt zu schreiben (falls es noch nicht vorhanden ist), anstatt es sofort zu protokollieren. Wenn Sie sich auf einer niedrigen Ebene anmelden, müssen Sie dennoch eine Ausnahme auslösen, um Ihren Anrufern mitzuteilen, dass Sie Ihren Job nicht abgeschlossen haben. Dies führt zu mehreren Protokollen desselben Ereignisses.

Ausnahmen

Meine wichtigste Richtlinie ist, Ausnahmen nur auf oberster Ebene zu erfassen und zu protokollieren. Und alle Ebenen darunter sollten sicherstellen, dass alle erforderlichen Fehlerinformationen auf die oberste Ebene übertragen werden. In einer Einzelprozessanwendung, z. B. in Java, bedeutet dies meistens, überhaupt nicht außerhalb der obersten Ebene zu versuchen / zu fangen oder zu protokollieren.

Manchmal möchten Sie einige Kontextinformationen in das Ausnahmeprotokoll aufnehmen, die in der ursprünglichen Ausnahme nicht verfügbar sind, z. B. die SQL-Anweisung und die Parameter, die ausgeführt wurden, als die Ausnahme ausgelöst wurde. Dann können Sie die ursprüngliche Ausnahme abfangen und eine neue auslösen, die die ursprüngliche Ausnahme plus den Kontext enthält.

Natürlich stört das wirkliche Leben manchmal:

  • In Java müssen Sie manchmal eine Ausnahme abfangen und in einen anderen Ausnahmetyp umbrechen, um einige feste Methodensignaturen zu beachten. Wenn Sie jedoch eine Ausnahme erneut auslösen, stellen Sie sicher, dass die erneut ausgelöste alle Informationen enthält, die für die spätere Protokollierung erforderlich sind.

  • Wenn Sie eine Grenze zwischen Prozessen überschreiten, können Sie technisch häufig nicht das gesamte Ausnahmeobjekt einschließlich des Stack-Trace übertragen. Und natürlich kann die Verbindung verloren gehen. Hier ist also ein Punkt, an dem ein Dienst Ausnahmen protokollieren und dann versuchen sollte, so viele Fehlerinformationen wie möglich über die Leitung an den Client zu übertragen. Der Dienst muss sicherstellen, dass der Client eine Fehlermeldung erhält, indem er entweder eine Fehlerantwort erhält oder bei einer unterbrochenen Verbindung eine Zeitüberschreitung feststellt. Dies führt normalerweise dazu, dass derselbe Fehler zweimal protokolliert wird, einmal innerhalb des Dienstes (mit mehr Details) und einmal auf der obersten Ebene des Clients.

Protokollierung

Ich füge einige Sätze zum Protokollieren im Allgemeinen hinzu, nicht nur zum Protokollieren von Ausnahmen.

Neben Ausnahmesituationen möchten Sie, dass wichtige Aktivitäten Ihrer Anwendung auch im Protokoll aufgezeichnet werden. Verwenden Sie daher ein Protokollierungsframework.

Seien Sie vorsichtig mit den Protokollebenen (das Lesen von Protokollen, in denen Debug-Informationen und schwerwiegende Fehler nicht mit unterschiedlichen gekennzeichnet sind, ist schmerzhaft!). Typische Protokollebenen sind:

  • FEHLER: Einige Funktionen sind unwiederbringlich ausgefallen. Das bedeutet nicht unbedingt, dass Ihr gesamtes Programm abgestürzt ist, aber einige Aufgaben konnten nicht abgeschlossen werden. In der Regel haben Sie ein Ausnahmeobjekt, das den Fehler beschreibt.
  • WARNUNG: Es ist etwas Seltsames passiert, aber es ist keine Aufgabe fehlgeschlagen (seltsame Konfiguration erkannt, vorübergehender Verbindungsabbruch, einige Wiederholungsversuche usw.)
  • INFO: Sie möchten dem lokalen Systemadministrator einige wichtige Programmaktionen mitteilen (Starten eines Dienstes mit seiner Konfiguration und Softwareversion, Importieren von Datendateien in die Datenbank, Anmelden von Benutzern am System, Sie haben die Idee ...).
  • DEBUG: Dinge, die Sie als Entwickler sehen möchten, wenn Sie ein Problem debuggen (aber Sie werden nie im Voraus wissen, was Sie wirklich für diesen oder jenen bestimmten Fehler benötigen - wenn Sie es vorhersehen können, werden Sie den Fehler beheben ). Eine Sache, die immer nützlich ist, ist das Protokollieren von Aktivitäten auf externen Schnittstellen.

Setzen Sie in der Produktion die Protokollebene auf INFO. Die Ergebnisse sollten für einen Systemadministrator nützlich sein, damit er weiß, was los ist. Erwarten Sie von ihm, dass er Sie für jeden FEHLER im Protokoll und in der Hälfte der WARNUNGEN um Hilfe oder Fehlerbehebung bittet.

Aktivieren Sie die DEBUG-Stufe nur während echter Debugsitzungen.

Gruppieren Sie die Protokolleinträge in entsprechende Kategorien (z. B. nach dem vollqualifizierten Klassennamen des Codes, der den Eintrag generiert), sodass Sie Debug-Protokolle für bestimmte Teile Ihres Programms aktivieren können.

Ralf Kleberhoff
quelle
Vielen Dank für eine so ausführliche Antwort. Ich schätze auch den Protokollierungsteil sehr.
KidCode
-1

Ich bereite mich auf die Abstimmungen vor, aber ich werde mich auf die Beine stellen und sagen, ich bin nicht sicher, ob ich dem zustimmen kann.

Das Aufblähen von Ausnahmen und noch weniger das erneute Aufzeichnen von Ausnahmen ist ein zusätzlicher Aufwand mit geringem Nutzen. Fangen Sie die Ausnahme an der Quelle ab (ja, am einfachsten), protokollieren Sie sie, aber lösen Sie die Ausnahme dann nicht erneut aus, sondern melden Sie dem Aufrufer nur "Fehler". "-1", null, leere Zeichenfolge, eine Aufzählung, was auch immer. Der Anrufer muss nur wissen, dass der Anruf fehlgeschlagen ist, fast nie die grauenhaften Details. Und die werden in deinem Logbuch sein, oder? In dem seltenen Fall, dass der Anrufer die Details benötigt, gehen Sie voran und sprudeln Sie, aber nicht als automatischer undenkbarer Standard.

mickeyf_supports_Monica
quelle
3
Das Problem beim Melden des Fehlers nach Rückgabewerten ist: 1. Wenn sich der Aufrufer um Fehler kümmert, muss er den speziellen Wert überprüfen. Aber warten Sie, ist es nulloder die leere Zeichenfolge? Ist es -1 oder eine negative Zahl? 2. Wenn es den Anrufer nicht interessiert (dh nicht prüft), führt dies zu Fehlern, die nicht mit der ursprünglichen Ursache zusammenhängen, z NullPointerException. B. a . Oder schlimmer: Die Berechnung wird mit falschen Werten fortgesetzt. 3. Wenn es den Aufrufer interessieren würde, aber der Programmierer denkt, dass diese Methode fehlschlägt, erinnert ihn der Compiler nicht daran. Ausnahmen haben diese Probleme nicht, entweder Sie fangen oder Sie werfen um.
Siegi
1
Entschuldigung, ich musste das ablehnen. Der Ansatz, den Sie beschreiben (Ausnahmen durch spezielle Rückgabewerte ersetzen), war in den 1970er Jahren, als die C-Sprache entstand, Stand der Technik, und es gibt viele gute Gründe, warum moderne Sprachen Ausnahmen haben, und für mich ist dies der wichtigste Die ordnungsgemäße Verwendung von Ausnahmen erleichtert das Schreiben von stabilem Code erheblich. Und Ihr "Sprudeln von Ausnahmen [...] ist zusätzlicher Aufwand [...]" ist eindeutig falsch: Tun Sie nichts gegen Ausnahmen, und sie sprudeln von alleine.
Ralf Kleberhoff