Sentry — трекинг java exception в Java

15 ИЮНЯ 2022

------------------------------------------------------------------------

Наш телеграм-канал: t.me/@mailsgun_online

Youtube: youtube.com/@mailsgun_online

------------------------------------------------------------------------

Sentry — трекинг java exception в Java

Стандартно Java разработчики мониторят ошибки, exception через логи. Но есть и другой способ, а именно отправка exception в Sentry.

Sentry — инструмент мониторинга исключений (exception), ошибок в ваших приложениях.

Преимущества использования Sentry:

  • не нервничать при размещении приложений на боевом сервере,

  • быстро находить причины возникших проблем,

  • устранять баги раньше, чем о них вам сообщат тестировщики, коллеги из саппорта, пользователи, ПМ или директор,

  • выявлять незаметные остальной команде проблемы, которые портят жизнь пользователям и снижают эффективность вашего продукта,

  • бесплатен,

  • легко интегрируется в проект,

  • ловит ошибки и в браузере пользователя, и на вашем сервере.

  • Если в ELK один и тот же exception происходит несколько раз, то они идут как отдельные записи, занимают место на диске и в ОЗУ. Если в Sentry один и тот же exception происходит несколько раз, то поле EVENTS увеличивается, тем самым экономя место на диске и в ОЗУ. Пример

    Основные возможности:

  • Список ошибок обновляется в режиме реального времени,

  • Если ошибка была помечена как решенная и появилась снова, то она снова создается и учитывается в отдельном потоке,

  • Ошибки группируются и отображаются в порядке частоты появления,

  • Ошибки можно фильтровать по статусам, источнику логгирования, уровню логгирования, имени сервера и т.д.

Sentry поддерживает большую часть языков программирования. Подробнее здесь.

Устанавливаем Sentry

  • через скрипт, который в docker-compose поднимет все компоненты (скрипт и репо находятся здесь https://github.com/getsentry/onpremise/)
  • собираем RPM пакеты все зависимостей Sentry и устанавливаем через RPM пакеты https://habr.com/ru/post/500632/

После установки Sentry у вас должен быть DSN

Здесь будет обзор основных примеров отправки java exception в Sentry. Примеры будем брать из официального репозитория https://github.com/getsentry/examples/tree/master/java.

Зависимости

На машине где будете запускать эти примеры необходимо иметь установленными JDK и Maven.

# Пример для CentOS
wget http://repos.fedorapeople.org/repos/dchen/apache-maven/epel-apache-maven.repo -O /etc/yum.repos.d/epel-apache-maven.repo
yum install -y apache-maven java-1.8.0-openjdk-devel git

Скачиваем репозиторий

git clone https://github.com/getsentry/examples.git
cd examples/java/

Sentry Basic Example

Переходим к https://github.com/getsentry/examples/tree/master/java/basic

cd basic

Запускаем компилирование проекта

mvn compile exec:java

Запускаем Java приложение и передаем ему SENTRY_DSN

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 mvn exec:java

Как выглядят exception в Sentry

Запустим приложение несколько раз:

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 mvn exec:java

Видно что счетчик EVENTS для этого конкретного exception увеличился. Скриншот в начале поста.

Sentry Grails Example

Переходим к https://github.com/getsentry/examples/tree/master/java/grails-3.x

Устанавливаем зависимости для SDK

yum install -y unzip zip

Устанавливаем grails используя SDK https://grails.org/download.html

curl -s https://get.sdkman.io | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install grails

Запускаем grails c SENTRY_DSN

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 grails run-app

Открываем в браузере http://localhost:8080/hello/index и exception отправляются в Sentry

Как выглядят exception в Sentry

Запустим приложение несколько раз:

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 grails run-app

Видно что счетчик EVENTS для этого конкретного exception увеличился.

Sentry java.util.logging Example

Переходим к https://github.com/getsentry/examples/tree/master/java/java.util.logging

Собираем пакет JAR

mvn clean package

Запускаем JAR

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 
java 
-Djava.util.logging.config.file=src/main/resources/logging.properties 
-cp ./target/sentry-java-jul-example-1.0-SNAPSHOT-jar-with-dependencies.jar 
io.sentry.example.Application

Как выглядят exception в Sentry

Sentry Log4j 1.x Example

Переходим к https://github.com/getsentry/examples/tree/master/java/log4j-1.x

Компилируем

mvn compile exec:java

Запускаем

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 mvn exec:java

Как выглядят exception в Sentry

Sentry Log4j 2.x Example

Переходим к https://github.com/getsentry/examples/tree/master/java/log4j-2.x

Компилируем

mvn compile exec:java

Запускаем

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 mvn exec:java

Как выглядят exception в Sentry

Sentry Logback Example

Переходим к https://github.com/getsentry/examples/tree/master/java/logback

Компилируем

mvn compile exec:java

Запускаем

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 mvn exec:java

Как выглядят exception в Sentry

Sentry Spring Boot Example

Переходим к https://github.com/getsentry/examples/tree/master/java/spring-boot

Запускаем

SENTRY_DSN=http://31bc93d7d64e4fd6b2e77d6d7780be6c@172.26.10.64:9000/1 mvn spring-boot:run

Открываем в браузере http://localhost:8080/ и exception отправляются в Sentry

В логах мы видим

2020-06-20 12:35:47.249 ERROR 13939 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ArithmeticException: / by zero] with root cause
java.lang.ArithmeticException: / by zero
    at io.sentry.example.Application.home(Application.java:44) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_252]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_252]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_252]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_252]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_252]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_252]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_252]

В http://localhost:8080/ мы видим:

Как выглядят exception в Sentry

Телеграм чат по Sentry https://t.me/sentry_ru

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Используете ли вы трекинг exception, как например Sentry?

  • 20,0%Да, использую локальный вариант2
  • 30,0%Да, использую облачный вариант3
  • 10,0%Да, планирую ипользовать1
  • 0,0%Нет, я думал Sentry платный и только в облаке0
  • 30,0%Нет, мне хватает логов в Kibana3
  • 30,0%Нет, я не знал о трекинге exception как направление3
Проголосовали 10 пользователей. Воздержались 5 пользователей.

Попробуете ли вы трекинг exception Sentry?

  • 66,7%Да, мне это интересно6
  • 22,2%Нет, мне хватает логов в Kibana2
  • 11,1%Я не понял как подключать Sentry SDK к своему коду1
Проголосовали 9 пользователей. Воздержались 5 пользователей.

Теги:
Хабы:


Source: habr1

Ну и напоследок напоминаю вам о нашем новом проекте vkserfing bot.