Czy bardziej sensowne jest rejestrowanie wyjątków w klasie catch-all lub w podstawowej klasie wyjątków?

15

Jestem w trakcie refaktoryzacji dość dużej aplikacji internetowej. Jednym z głównych problemów jest niespójna obsługa błędów i staram się wymyślić rozsądną strategię. Stworzyłem niestandardową procedurę obsługi błędów za pośrednictwem modułu obsługi błędów set_error_handler, który zasadniczo zamienia błędy PHP w wyjątkach ErrorExceptions oraz niestandardową podstawową klasę wyjątków, która bezpośrednio dziedziczy po wyjątku .

Podczas produkcji używam ogólnego wyjątku catch-all, poprzez moduł obsługi set_exception_handler i zamierzam dodać rejestrowanie wyjątków * do miksu. Moim dylematem jest faktyczne rejestrowanie, w podstawowej klasie wyjątków lub w trybie catch-all.

Zastanawiałem się nad kilkoma powodami, dla których warto zalogować się w całości:

  • Istnieje kilka wyjątków w kodzie, które należy przekonwertować na odpowiednie dziecko potomne podstawowej klasy wyjątków. Dopóki tak się nie stanie, nie wszystkie wyjątki zostaną zarejestrowane.
  • W jakiś sposób wydaje się to bardziej naturalne, gdy robi się to wszystko, podstawowa klasa wyjątków nie powinna robić więcej niż tylko to. (Może to być zasada jednej odpowiedzialności, ale może to być błędne uczucie)

i jeden powód, aby zalogować się do podstawowej klasy wyjątków:

  • Obecnie catch-all jest wykorzystywany tylko w produkcji. Łatwo byłoby wprowadzić go w naszych innych środowiskach (programowanie, testowanie), ale wymagałoby to kilku korekt, ponieważ błędy są obsługiwane inaczej w zależności od środowiska, ponieważ podczas produkcji są one tłumaczone na strony błędów 404/503.

Czy istnieje akceptowalna praktyka dotycząca rejestrowania wyjątków?

* Rejestrowanie będzie obejmować najpierw zapis do pliku tekstowego i może ewoluować do wysyłania wiadomości e-mail z pewnymi wyjątkami.


Niektóre wyjaśnienia pobudzony przez @ unholysampler za odpowiedź :

Stoję w obliczu bazy kodu 2 * 10 ^ 6, z dużą ilością rzeczy stron trzecich, nad którymi nie mam kontroli, a część kodu, który mam, kontroluje wyjątki w PHP przed datami wstępnymi. Jest też trochę gównianego kodu, który odzyskujemy po długim okresie intensywnej presji, w której praktycznie musieliśmy przestać myśleć i po prostu zhakować.

Aktywnie refaktoryzujemy się, aby zaradzić wszystkim niespójnościom i wprowadzić rozsądne podejście do obsługi błędów, ale to zajmie trochę czasu. Jestem bardziej zainteresowany tym, co robić, dopóki nie osiągnę punktu, w którym błędy są odpowiednio obsługiwane. W pewnym momencie prawdopodobnie zadam kolejne pytanie dotyczące rozsądnej strategii wyjątku.

Główną motywacją przy logowaniu jest otrzymywanie wiadomości e-mail na mój telefon za każdym razem, gdy wydarzy się coś złego w produkcji. Nie obchodzi mnie, czy zrzuty danych staną się ogromne, jeśli tak, to będę musiał co jakiś czas usuwać stare cron.

Yannis
źródło

Odpowiedzi:

11

Krótko mówiąc, jedynym wyjątkiem, kiedy powinieneś zarejestrować istnienie wyjątku, jest jego obsługa.

Gdy zgłaszasz wyjątek, dzieje się tak, ponieważ Twój kod osiągnął stan, w którym nie może działać poprawnie. Zgłaszając wyjątek, reprezentujesz konkretny komunikat dla swojego programu o zaistniałym błędzie. Nie powinieneś wychwytywać wyjątku, dopóki nie znajdziesz się w punkcie, w którym można go właściwie obsłużyć.

Kod, który piszesz jako część głównej aplikacji, powinien znać typy wyjątków, które mogą zostać zgłoszone i kiedy mogą zostać zgłoszone. Jeśli nie możesz zrobić nic produktywnego z wyjątkiem, nie łap go. Nie rejestruj wyjątku, dopóki nie zostanie obsłużony. Tylko kod obsługi wie, co oznacza wyjątek w kontekście przebiegu programu i jak na nie odpowiedzieć. Zapisanie tutaj dziennika może mieć sens. Jeśli używasz środowiska rejestrowania, możesz ustawić poziom dziennika dla wiadomości i potencjalnie je filtrować. Działa to dobrze w przypadku wyjątków, które mogą wystąpić, ale nie są krytyczne i można je odzyskać w czysty sposób.

Twój wyjątek to wszystko, co musisz zrobić, aby Twój kod nie uległ brzydkiej śmierci. Jeśli zaszedłeś tak daleko, rejestrujesz wszystkie informacje o stanie i błędach, jakie możesz. Następnie dokładasz wszelkich starań, aby miło powiedzieć użytkownikowi, że program ulega awarii, zanim wszystko się zatrzyma. Twoim celem nie powinno być nigdy wykonanie tego kodu.

Osadzanie logowania do klasy podstawowej nie jest zgodne z powyższymi wytycznymi. Klasa podstawowa nic nie wie o stanie kodu. (Śledzenie stosu nie ma znaczenia, ponieważ nie zamierzasz pisać kodu, który podejmuje decyzje na podstawie jego analizy). Klasa podstawowa nie może nic zrobić, aby wskazać istotność lub sposób obsługi wyjątku. Nie chcesz dużych zrzutów danych i śladów stosu za każdym razem, gdy istnieje prosty wyjątek, z którego możesz sobie poradzić i odzyskać po nim.

unholysampler
źródło
Dodałem kilka wyjaśnień do pytania podpowiedzianego przez twoją odpowiedź. Z tego, co zbieram, po praktycznej stronie pytania, które proponujesz zalogować się w trybie catch-all?
yannis
1
@YannisRizos: Tak, powinieneś wdrożyć catch-all jako pierwszy krok. To, co powiedziałem o catch-all, miało na celu zapewnienie, że nie użyjesz go jako normalnej części przepływu kodu. Wdrożenie nieobsługiwanego modułu obsługi wyjątków jest ważne, ponieważ pozwala uzyskać wiele informacji za każdym razem, gdy kod robi coś złego.
unholysampler
Czy nie ma żadnych ram rejestrowania, które wygodnie poradziłyby sobie z koncepcją „Oto kilka rzeczy, które należy zalogować, chyba że zostaną zastąpione”? Każda warstwa, która widzi wyjątek, może zastąpić dane z poprzedniego, z wyjątkiem tego, że jeśli nowy wyjątek zostanie zgłoszony w trakcie rozwijania stosu, ostatni raport dziennika nie zostanie zastąpiony, a zatem zostanie zapisany. Czy żadne ramy nie obsługują takiego wzorca?
supercat
3

Jeśli Twój język / środowisko wykonawcze nie pozwala łatwo określić źródła wyjątku, istnieje możliwość zarejestrowania go przy rzucie. C ++ i niektóre silniki JS nie ujawniają stosu pliku + linii lub wywołania wyjątku do momentu jego złapania / ale ta informacja jest dostępna w momencie konstruowania wyjątku.

Naszym rozwiązaniem było zapewnienie mechanizmu, który używał konfiguracji środowiska wykonawczego, aby umożliwić rejestrowanie typu wyjątku wraz z tanim stosem podczas próby zdiagnozowania tych problemów.

JBRWilkinson
źródło
+1 To zdecydowanie dobry przypadek na zalogowanie się na rzut ... PHP zapewnia jednak śledzenie pełnego stosu przy złapaniu, więc prawdopodobnie pójdę w drugą stronę ...
yannis