Architettura multilivello: dove dovrei implementare la registrazione e la gestione degli errori?


17

Attualmente sto eseguendo il refactoring di un sottosistema di grandi dimensioni con un'architettura a più livelli e sto lottando per progettare un'efficace strategia di gestione e registrazione degli errori.

Diciamo che la mia architettura è composta dai seguenti tre livelli:

  • Interfaccia pubblica (IE un controller MVC)
  • Livello di dominio
  • Livello di accesso ai dati

La mia fonte di confusione è dove dovrei implementare la registrazione e la gestione degli errori:

  1. La soluzione più semplice sarebbe quella di implementare la registrazione al livello più alto (ovvero l'interfaccia pubblica \ controller MVC). Tuttavia, questo sembra sbagliato perché significa gorgogliare l'eccezione attraverso i diversi livelli e quindi registrarla; piuttosto che registrare l'eccezione alla sua fonte.

  2. Registrare l'eccezione alla sua fonte è ovviamente la soluzione migliore perché ho la maggior parte delle informazioni. Il mio problema con questo è che non riesco a catturare tutte le eccezioni alla fonte senza catturare TUTTE le eccezioni, e nel livello dell'interfaccia pubblico / di dominio, questo porterà a catturare le eccezioni che sono già state catturate, registrate e ri-generate dal livello sottostante .

  3. Un'altra possibile strategia è un mix di # 1 e # 2; per cui rilevo specifiche eccezioni a livello che molto probabilmente vengono generate (cattura IE, registrazione e rilancio SqlExceptionsnel livello di accesso ai dati) e quindi registro tutte le ulteriori eccezioni non rilevate al livello superiore. Tuttavia, ciò richiederebbe anche di rilevare e registrare nuovamente ogni eccezione al livello più alto, perché non riesco a distinguere tra errori che sono già stati registrati \ gestiti rispetto a quelli che non lo sono.

Ora, ovviamente, questo è un problema nella maggior parte delle applicazioni software, quindi ci deve essere una soluzione standard a questo problema che si traduca in eccezioni catturate alla fonte e registrate una volta; tuttavia non riesco proprio a vedere come farlo da solo.

Nota, il titolo di questa domanda è molto simile a " Registrazione delle eccezioni in un'applicazione multilivello" ", tuttavia le risposte in quel post mancano di dettagli e non sono sufficienti per rispondere alla mia domanda.


1
Un approccio che a volte uso è quello di creare la mia sottoclasse Exception (o RuntimeException) e lanciarla, inclusa l'eccezione originale come nidificata. Ovviamente significa che quando si acquisiscono eccezioni ai livelli superiori, è necessario verificare il tipo di eccezione (le mie eccezioni vengono appena riproposte, altre eccezioni vengono registrate e incluse in nuove istanze delle mie eccezioni). Ma ho lavorato da solo per molto tempo, quindi non posso dare consigli "ufficiali".
SJuan76,

4
The easiest solution would be to implement the logging at the top level- Fai questo. La registrazione delle eccezioni alla loro fonte non è una buona idea e ogni applicazione che ho riscontrato è stata una PITA per il debug. Dovrebbe essere responsabilità del chiamante gestire le eccezioni.
Giustino,

Sembra che tu abbia in mente una specifica tecnica / linguaggio di implementazione, altrimenti la tua affermazione "le eccezioni che sono state registrate sono indistinguibili da quelle che non lo erano" è difficile da capire. Puoi dare più contesto?
Vroomfondel,

@Vroomfondel - Hai ragione. Sto usando C #, e racchiudendo il codice in ogni livello si try{ ... } catch(Exception ex) { Log(ex); }otterrebbe la stessa eccezione registrata su ogni livello. (Sembra anche una cattiva pratica catturare ogni eccezione in ogni livello della base di codice.)
Kid

Risposte:


18

Alle tue domande:

La soluzione più semplice sarebbe quella di implementare la registrazione al massimo livello

Avere la bolla delle eccezioni al massimo livello è un approccio assolutamente corretto e plausibile. Nessuno dei metodi di livello superiore tenta di continuare un processo dopo l'errore, che in genere non riesce. E un'eccezione ben attrezzata contiene tutte le informazioni necessarie per la registrazione. E non fare nulla riguardo alle eccezioni ti aiuta a mantenere il codice pulito e focalizzato sull'attività principale anziché sugli errori.

Registrare l'eccezione alla sua fonte è ovviamente la soluzione migliore perché ho la maggior parte delle informazioni.

È mezzo corretto. Sì, le informazioni più utili sono disponibili qui. Ma consiglierei di inserire tutto questo nell'oggetto eccezione (se non è già presente) invece di registrarlo immediatamente. Se accedi a un livello basso, devi comunque sollevare un'eccezione per dire ai chiamanti che non hai completato il lavoro. Questo finisce in più registri dello stesso evento.

eccezioni

La mia linea guida principale è catturare e registrare le eccezioni solo al livello più alto. E tutti i livelli sottostanti dovrebbero assicurarsi che tutte le informazioni di errore necessarie vengano trasportate al livello superiore. All'interno di un'applicazione a processo singolo, ad esempio in Java, ciò significa principalmente non provare / catturare o accedere al di fuori del livello superiore.

A volte, si desidera includere nel registro delle eccezioni alcune informazioni di contesto che non sono disponibili nell'eccezione originale, ad esempio l'istruzione SQL e i parametri che sono stati eseguiti quando è stata generata l'eccezione. Quindi puoi catturare l'eccezione originale e rilanciarne una nuova, contenente quella originale più il contesto.

Certo, la vita reale a volte interferisce:

  • In Java, a volte devi catturare un'eccezione e racchiuderla in un diverso tipo di eccezione solo per obbedire ad alcune firme del metodo fisso. Ma se si respinge un'eccezione, assicurarsi che quella rilanciata contenga tutte le informazioni necessarie per la registrazione successiva.

  • Se si attraversa un bordo tra processi, spesso tecnicamente non è possibile trasferire l'intero oggetto eccezione compreso la traccia dello stack. E ovviamente la connessione potrebbe andare persa. Quindi, ecco un punto in cui un servizio dovrebbe registrare le eccezioni e quindi fare del suo meglio per trasmettere al client il maggior numero possibile di informazioni sull'errore attraverso la linea. Il servizio deve assicurarsi che il client riceva una notifica di errore, ricevendo una risposta di errore o eseguendo un timeout in caso di interruzione della connessione. Questo di solito comporterà la registrazione dello stesso errore due volte, una volta all'interno del servizio (con maggiori dettagli) e una volta al livello principale del client.

Registrazione

Sto aggiungendo alcune frasi sulla registrazione in generale, non solo sulla registrazione delle eccezioni.

Oltre a situazioni eccezionali, si desidera che anche le attività importanti dell'applicazione vengano registrate nel registro. Quindi, utilizzare un framework di registrazione.

Prestare attenzione ai livelli di registro (leggere i registri in cui le informazioni di debug e gli errori gravi non sono contrassegnati con differenze di conseguenza è una seccatura!). I livelli di registro tipici sono:

  • ERRORE: alcune funzioni sono fallite irrimediabilmente. Ciò non significa necessariamente che l'intero programma si sia bloccato, ma alcune attività non possono essere completate. In genere, si dispone di un oggetto eccezione che descrive l'errore.
  • ATTENZIONE: si è verificato qualcosa di strano, ma non ha causato alcun errore (è stata rilevata una strana configurazione, un'interruzione temporanea della connessione che causa alcuni tentativi, ecc.)
  • INFO: vuoi comunicare alcune importanti azioni del programma all'amministratore di sistema locale (avviare un servizio con la sua configurazione e versione del software, importare file di dati nel database, utenti che accedono al sistema, hai l'idea ...).
  • DEBUG: cose che lo sviluppatore desidera vedere quando si esegue il debug di un problema (ma non si saprà mai in anticipo cosa è realmente necessario in caso di questo o quel bug specifico - se è possibile prevederlo, si correggerà il bug ). Una cosa che è sempre utile è registrare le attività su interfacce esterne.

In produzione, impostare il livello di registro su INFO. I risultati dovrebbero essere utili a un amministratore di sistema in modo che sappia cosa sta succedendo. Aspettati che ti chiami per assistenza o correzione di errori per ogni errore nel registro e per metà degli AVVERTENZE.

Abilitare il livello DEBUG solo durante le sessioni di debug reali.

Raggruppare le voci del registro in categorie appropriate (ad es. In base al nome di classe completo del codice che genera la voce), consentendo di attivare i registri di debug per parti specifiche del programma.


Grazie per una risposta così dettagliata, apprezzo molto anche la parte di registrazione.
Kid

-1

Mi sto preparando per i voti negativi, ma sto andando fuori di testa e dire che non sono sicuro di poter essere d'accordo con questo.

Le eccezioni gorgoglianti, e tanto meno la registrazione di nuovo, sono uno sforzo extra con pochi benefici. Cattura l'eccezione alla fonte (sì, la più semplice), registrala, ma poi non ripetere l'eccezione, riporta semplicemente "errore" al chiamante. "-1", null, stringa vuota, qualche enum, qualunque cosa. Il chiamante deve solo sapere che la chiamata non è riuscita, quasi mai i dettagli raccapriccianti. E quelli saranno nel tuo registro, giusto? Nel raro caso in cui il chiamante abbia bisogno dei dettagli, vai avanti e fai il bubble up, ma non come impostazione predefinita non pensante automatica.


3
Il problema con la segnalazione dell'errore in base ai valori restituiti è: 1. Se il chiamante si preoccupa degli errori, deve controllare il valore speciale. Ma aspetta, è nullo la stringa vuota? È -1 o un numero negativo? 2. Se al chiamante non interessa (ovvero non verifica), ciò porta a follow-up di errori non correlati alla causa originale, ad es NullPointerException. A. O peggio: il calcolo continua con valori errati. 3. Se al chiamante interessa, ma il programmatore non pensa che questo metodo fallisca, il compilatore non gli ricorda. Le eccezioni non hanno questi problemi, o catturi o ripeti.
siegi,

1
Mi dispiace, ho dovuto ridimensionarlo. L'approccio che descrivi (sostituisci le eccezioni con valori di ritorno speciali) era all'avanguardia negli anni '70, quando ebbe origine il linguaggio C, e ci sono molte buone ragioni per cui le lingue moderne hanno eccezioni, e per me la principale è che l'uso corretto delle eccezioni rende molto più semplice scrivere codice affidabile. E le tue "Eccezioni gorgoglianti [...] sono uno sforzo extra [...]" è chiaramente sbagliato: non fare nulla riguardo alle eccezioni e si riempiranno di bolle da sole.
Ralf Kleberhoff,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.