È più sensato registrare le eccezioni in una classe catch-all o in una classe di eccezioni di base?


15

Sto eseguendo il refactoring di un'app Web abbastanza grande. Uno dei problemi principali è la gestione degli errori incoerente e sto cercando di elaborare una strategia ragionevole. Ho creato un gestore di errori personalizzato, tramite set_error_handler che essenzialmente trasforma gli errori PHP in ErrorExceptions e una classe di eccezioni di base personalizzata, che eredita direttamente da Exception .

In produzione sto usando un'eccezione generica catch-all, tramite set_exception_handler , e sto per aggiungere la registrazione delle eccezioni * al mix. Il mio dilemma è dove effettuare la registrazione effettiva, nella classe di eccezioni di base o nel catch-all.

Ho pensato a un paio di motivi per registrarlo nel catch-all:

  • Esistono alcune eccezioni nel codice che devono essere convertite in un figlio appropriato della classe di eccezioni di base. Fino a quando ciò non accadrà, non tutte le eccezioni verranno registrate.
  • In qualche modo sembra più naturale farlo nel complesso, una classe di eccezioni di base non dovrebbe fare altro che essere proprio questo. (Potrebbe essere una sola cosa del principio di responsabilità, ma potrebbe essere solo una sensazione fuorviante)

e un motivo per accedere alla classe di eccezione di base:

  • Attualmente il catch-all è utilizzato solo in produzione. Sarebbe facile introdurlo negli altri nostri ambienti (sviluppo, test) ma ciò richiederebbe alcuni aggiustamenti, poiché gli errori vengono gestiti in modo diverso per ambiente, poiché sulla produzione vengono tradotti in pagine di errore 404/503.

Esistono pratiche accettabili su dove registrare le eccezioni?

* La registrazione comporterà inizialmente la scrittura in un file di testo e potrebbe evolversi nell'invio di posta per determinati tipi di eccezioni.


Alcuni chiarimenti, spinti dalla risposta di @ unholysampler :

Sto affrontando una base di codice sloc 2 * 10 ^ 6, con molte cose di terze parti su cui non ho alcun controllo e parte del codice che ho controllo sulle eccezioni precedenti a PHP. E c'è anche un pessimo codice recente, ci stiamo riprendendo da un lungo periodo di intensa pressione in cui abbiamo praticamente dovuto smettere di pensare e solo hackerato.

Stiamo attivamente effettuando il refactoring per affrontare tutte le incoerenze e introdurre un approccio ragionevole alla gestione degli errori, ma ci vorrà del tempo. Sono più interessato a cosa fare fino a quando non raggiungo il punto in cui gli errori vengono gestiti in modo appropriato. Probabilmente farò un'altra domanda su una strategia di eccezione ragionevole ad un certo punto.

La motivazione principale alla base della registrazione è quella di ricevere un'e-mail sul mio telefono ogni volta che succede qualcosa di brutto durante la produzione. Non mi importa se i dump di dati diventano enormi, se lo fanno avrò un lavoro cron che elimina quelli vecchi di tanto in tanto.

Risposte:


11

In breve, l'unica volta in cui dovresti registrare l'esistenza di un'eccezione è quando la gestisci.

Quando si genera un'eccezione, è perché il codice ha raggiunto uno stato in cui non può procedere correttamente. Lanciando un'eccezione, stai rappresentando un messaggio specifico al tuo programma sull'errore che si è verificato. Non si dovrebbe prendere un'eccezione fino a quando non si è in un punto in cui può essere gestita correttamente.

Il codice che scrivi come parte della tua applicazione principale dovrebbe essere consapevole dei tipi di eccezioni che possono essere lanciate e quando potrebbero essere lanciate. Se non puoi fare nulla di produttivo con un'eccezione, non prenderlo. Non registrare un'eccezione fino a quando non viene gestita. Solo il codice di gestione sa cosa significa l'eccezione nel contesto del flusso del programma e come rispondere ad esso. Scrivere un messaggio di log qui può avere senso qui. Se si utilizza un framework di registrazione, è possibile impostare un livello di registro per il messaggio e potenzialmente filtrarlo. Questo funziona bene per le eccezioni che possono verificarsi, ma non sono critiche e possono essere recuperate in modo pulito.

La tua eccezione, tutto sommato, è il tuo ultimo disperato tentativo di impedire al tuo codice di provocare una brutta morte. Se sei arrivato così lontano, registri tutte le informazioni di stato e di errore che puoi. Quindi fai del tuo meglio per dire all'utente che il programma si sta arrestando in modo anomalo prima che tutto si interrompa. Il tuo obiettivo dovrebbe essere quello di non eseguire mai questo codice.

Incorporare la registrazione nella classe base non segue le linee guida sopra. La classe base non sa nulla dello stato del codice. (Avere la traccia dello stack non conta perché non hai intenzione di scrivere codice che prende decisioni in base all'analisi.) La classe base non può fare nulla per indicare la gravità o il modo in cui l'eccezione potrebbe essere gestita. Non vuoi enormi dump di dati e tracce di stack ogni volta che esiste una semplice eccezione che puoi gestire e ripristinare in modo pulito.


Ho aggiunto alcuni chiarimenti alla domanda posta dalla tua risposta. Da quello che raccolgo, sul lato pratico della domanda che proponi di accedere al catch-all?
yannis,

1
@YannisRizos: Sì, dovresti implementare il catch-all come primo passo. Quello che ho detto sul catch-all è stato di più per assicurarti di non averlo usato come parte normale del tuo flusso di codice. L'implementazione di un gestore di eccezioni non gestite è importante perché ti consente di ottenere molte informazioni ogni volta che il tuo codice fa qualcosa di male.
unholysampler,

Non ci sono framework di logging che possano gestire comodamente il concetto di "Ecco un mucchio di cose che dovrebbero essere registrate a meno che non vengano sostituite"? Ogni layer che vede un'eccezione potrebbe sostituire i dati del precedente, tranne per il fatto che se una nuova eccezione venisse lanciata nel corso dello stack svolgendo il report dell'ultimo registro non verrebbe sostituito e verrebbe quindi registrato. Nessun framework supporta tale schema?
supercat

3

Se la tua lingua / runtime non ti consente di determinare facilmente l'origine dell'eccezione, è necessario registrarla immediatamente. C ++ e alcuni motori JS non espongono il file + linea o lo stack di chiamate dell'eccezione nel momento in cui l'hai rilevata / ma queste informazioni sono disponibili al momento della creazione dell'eccezione.

La nostra soluzione era fornire un meccanismo che utilizzava la configurazione di runtime per consentire la registrazione del tipo di eccezione insieme a uno stack economico quando si tenta di diagnosticare questi problemi.


+1 Questo è sicuramente un buon caso per accedere al tiro ... PHP fornisce comunque una traccia dello stack completo, quindi probabilmente andrò dall'altra parte ...
yannis,
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.