Как мониторить исключения в приложении без доступа к IDE и ручному просмотру логов
Что проверяют
Знаете ли вы, как ошибки с прода сами доходят до команды: агрегация, алерты, связка с трассировкой. Следом спрашивают, как отличить новую ошибку от старой, которая сыплется тысячами, и как не утопить команду в уведомлениях.
Как отвечать
Стройте ответ слоями, от «узнать» до «разобраться»:
- трекер ошибок: Sentry или совместимый с ним self-hosted GlitchTip. SDK для Spring Boot сам ловит необработанные исключения, группирует их по стеку, показывает число событий, первое появление, релиз, пользователя и хлебные крошки. Уведомление приходит на новую группу, а не на каждое событие;
- централизованные логи: не файлы на сервере, а структурированный JSON. В Spring Boot с версии 3.4 есть встроенный structured logging (
logging.structured.format.console), раньше то же делали черезlogstash-logback-encoder. Дальше ELK, OpenSearch или Loki с Grafana и алерт на рост уровняERROR; - метрики: Actuator и Micrometer отдают в Prometheus метрику
http.server.requestsс тегамиstatusиexception. Алерт в Alertmanager на долю 5xx надёжнее, чем реакция на отдельные записи; - трассировка: OpenTelemetry Java agent подключается через
-javaagent, исключение попадает в спан как событие, аtraceIdв MDC связывает строку лога с полным путём запроса через сервисы; - где ловить:
@RestControllerAdviceдля HTTP,Thread.setDefaultUncaughtExceptionHandlerдля голых потоков,AsyncUncaughtExceptionHandlerдля@Asyncметодов без результата.
Где спотыкаются
Теряют стек: log.error(e.getMessage()) вместо log.error("Не удалось списать", e). В мониторинг приезжает строка без причины, и группировка по стеку не работает.
Считают, что UncaughtExceptionHandler ловит всё. Исключение из задачи, отправленной через ExecutorService.submit, оседает внутри Future и никуда не всплывает, пока кто-то не вызовет get().
Шлют алерт на каждое исключение. Через неделю канал уведомлений все отключают. Алертить нужно на новую группу ошибок и на рост частоты относительно нормы.