Sentry Springboot

Sentry Springboot

Sentry is one of the most powerful tools I have come across to get error alerting and it shortens the time from detecting an issue to fixing the issue.

Ten error logs are simple to handle, but a storm of errors at 2 am is a developers worst night name.

What problem does Sentry solve?

For developers

  • Sentry SaaS is easy to configure OR you can host it yourself.
  • To send an issue to Sentry, all you need to do is write a log.error()
  • All similar errors are put into a single issue. So 1 error that happens 10,000 is a single issue that links to the 10,000 accurses.
  • Bugs are picked up faster and can be detected before a user reports the issue.

For people paying for Sentry

  • A bug in production costs reputation and costs hours to debug in production.
  • The faster a bug can be detected and resolved has obvious benefits for the above.
  • Bugs are picked up faster and can be detected before a user reports the issue.

Setting up the example code

This is a simple project that demonstrates how to setup Sentry SaaS and how to trigger two issues. Instructions to setup the Springboot Logback Maven project will follow below.

You can also setup Sentry in Kubernetes with this helm chart.

A simple issue

Consider this problematic example buggy code in Springboot that was introduced. It works great except if a user enters a by of zero, you would get an arithmetic error.

@GetMapping(path = "/divide")
public String division(@RequestParam Integer by) {
    return Integer.toString(100 / by);
}

Now consider if this bug did just occur once, but thousands of time.

Sentry identifies the issue via an email or Slack message:

  • There is an issue
  • When the issue started
  • How often the issue is happening
  • How many users are effected
  • Which version of the software introduced the bug

arithmetic-exception

From this point in Sentry you can:

  • Assign a person to look at the issue
  • Ignore the issue
  • Mark the issue as resolved and it occurs again you will get a regression message
  • Integrate with JIRA

When an error is not an error (false positive)

A common situation is when an error becomes normal.

Consider the error that occurs when a webcrawler cans your service and you get: favicon.ico not found

This error may be pushed to Sentry and then can be muted.

Warning

Sentry SaaS charges per call. So you should limit the amount of issues sent to Sentry

How to setup Springboot 4 with Sentry

Maven

Add these to your maven pom.xml

For more info refer to the Sentry documentation.

pom.xml
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-spring-boot-4-starter</artifactId>
</dependency>
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-logback</artifactId>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
</dependency>
pom.xml
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-spring-boot-starter-jakarta</artifactId>
</dependency>
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-logback</artifactId>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
</dependency>

Logback

Add a new logback.xml or and the Sentry appender

<configuration>
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="Sentry" class="io.sentry.logback.SentryAppender">
        <minimumEventLevel>ERROR</minimumEventLevel>
        <minimumBreadcrumbLevel>DEBUG</minimumBreadcrumbLevel>
    </appender>

    <!-- Enable the Console and Sentry appenders, Console is provided as an example
    of a non-Sentry logger that is set to a different logging threshold -->
    <root level="INFO">
        <appender-ref ref="Console"/>
        <appender-ref ref="Sentry"/>
    </root>
</configuration>

Add a Global Exception Handler

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public ProblemDetail handleException(Exception ex) {
        ProblemDetail problemDetail = ProblemDetail.forStatus(500);
        problemDetail.setTitle("Internal Server Error");
        problemDetail.setDetail(ex.getMessage());

        //send to Sentry via Logback
        log.atError().setMessage("Unknown Exception").setCause(ex).log();
        return problemDetail;
    }
}

Add non dynamic settings in a sentry profile

# Nondynamic settings for Sentry
sentry:
  send-default-pii: true
  logs:
    enabled: true

Start Sentry

SENTRY_DSN="Your Personal DSN"
SENTRY_ENVIRONMENT=development
SENTRY_RELEASE='my-sentry@0.1.0'

mvn spring-boot:run -Dspring-boot.run.profiles=sentry