← Back to Blog Home

Capturing Java Exceptions with Sentry

Capturing Java Exceptions with Sentry

Getting started with Java exception handling can be an intimidating prospect. The large number of dependency managers, logging frameworks, configuration methods, and programming languages that run on the JVM can create a dizzying number of options for a programmer to choose between, so we’ve put this guide together to help you navigate the world of modern Java error tracking with Sentry.

Choosing a Java Integration

The Sentry Java SDK (sentry-java) is hosted at Maven Central, a repository that hosts many widely distributed Java packages (JARs) and works with many of the popular JVM dependency managers, including Maven. A search for Sentry on Maven Central yields several results for different distributions of the project, and in this post we’ll help you figure out which is the right one to use with your application.

The major components of the SDK can be divided into two categories:

  • Logging integrations, commonly referred to as appenders, used to translate log records generated by your application via a logging framework into Sentry events. These integrations are packaged as sentry-logback,
sentry-log4j`, and `sentry-log4j2`.
- **Sentry**, used by the logging integrations to send events to a Sentry server.
This is packaged as `sentry` and also includes the logging handler for
`java.util.logging`.




For most applications, **we recommend using one of the logging integrations to
communicate with a Sentry server**, and we’ll be mainly focusing on those in
this post. For existing applications that are already using a logging
framework, integrating with Sentry is often as simple as adding or changing a
few lines in your logging configuration files. We recommend using the logging
integrations over interfacing with Sentry directly for several reasons:



- **The logging APIs are easy to understand.** The patterns and vocabulary used
by logging APIs are familiar to many developers, even across different
platforms.
- **Producing messages via the logging frameworks reduce the amount of
boilerplate code.** For example, compare the [logback appender event building
method](https://github.com/getsentry/sentry-java/blob/777eba2b1aa7044bc8abe8ecbcc040c522201dc9/sentry-logback/src/main/java/net/kencochrane/sentry/logback/SentryAppender.java#L176-L225) with [a call to the `logger.error` method](https://github.com/getsentry/sentry-java-examples/blob/62b90f1bb4ad940454c93de18ae7f4fa8bdc920e/sentry-java-logback-example/src/main/java/io/sentry/example/Application.java#L19).
- **Using a logging framework provides greater control over reporting
configuration.** It is easy to replace reporting to Sentry in your
development environment with console logging by using a different logging
configuration file. Contrast this with having to wrap all calls in
conditionals or mocking out the Sentry interface with a fake instance.
- **Many other libraries also utilize logging frameworks.** Using the logging
framework enables collecting better data from other libraries in your
application that also utilize the logging system, such as database drivers or
a web framework.




### The Java Logging Ecosystem



If you’re new to Java and have a background in a platform such as [Python](https://sentry.io/for/python/) with
a de facto logging solution, one of the first things that
you will notice is the large number of logging frameworks that are available
and remain used today. To understand why so many different frameworks exist,
we’ll start with a quick history lesson.



<EnhancedImage src="../../assets/images/posts/capturing-java-exceptions/inline-0.png" alt="image" />



Log4j was introduced in 1999 and was one of the first widely
adopted logging frameworks. A few years later in 2002, Sun introduced an
alternative framework, java.util.logging (commonly referred to by the acronym
“JUL”), which is distributed with the Java platform. In reaction, the Apache
Commons Logging project was created with the intention of providing a unified
logging API that could be used to interact with whichever backing logging
implementation that the user preferred, including Log4j and JUL (among others.)
However, yet another alternative “unified” logging API emerged in
2005 from the author of Log4j — SLF4J, the “Simple Logging Facade for Java.”
Later, the author of Log4j and SLF4J released logback, which provided a
native implementation of the SLF4J interface. Around the same time, development
also began on the (now stable) Log4j 2 — without the author of the first
version. Simple, right?



<EnhancedImage src="../../assets/images/posts/capturing-java-exceptions/inline-1.png" alt="Standards" />



There was a lot of code that was written at different points in time during
this history and like so much software there was — and still is — lot of
debates on which framework is the best choice. Since many of these projects are
still in use today, Sentry provides integrations for several of the most widely
adopted frameworks including [JUL](https://github.com/getsentry/sentry-java/tree/master/sentry), [logback](https://github.com/getsentry/sentry-java/tree/master/sentry-logback),
[Log4j](https://github.com/getsentry/sentry-java/tree/master/sentry-log4j), and [Log4j 2](https://github.com/getsentry/sentry-java/tree/master/sentry-log4j2). Getting started is typically
a matter of configuration, and the documentation for each integration contains
instructions on how to include the integration as a dependency as well as a
sample configuration to help you get started.



## Choosing the Right Integration for Your Projects



When choosing which logging framework to use for your own projects, that
decision is often mandated to you by your choice of framework. For projects
that don’t depend on a framework, targeting the SLF4J interface is often
recommended due to its ubiquity and flexibility. The backing logging
implementation is largely a matter of developer preference, with logback and
Log4j 2 being common choices.



## Starting from Scratch



For example, it only takes a few moments to start reporting to Sentry with
SLF4J and logback.



1. **Add **[**sentry-logback**](https://github.com/getsentry/sentry-java/tree/master/sentry-logback)** to your project dependencies.** If you’re using Maven,
dependencies are declared in `pom.xml`, and you can see an example [in our
logback example project](https://github.com/getsentry/sentry-java-examples/blob/62b90f1bb4ad940454c93de18ae7f4fa8bdc920e/sentry-java-logback-example/pom.xml#L19-L23). If you’re not using Maven,
the project details on Maven Central have dependency information for a variety
of different package managers.



` <dependency>
     <groupId>io.sentry</groupId>
     <artifactId>sentry-logback</artifactId>
     <version>1.2.0</version>
 </dependency>
  1. Add the Sentry appender to your**logback.xml**** configuration file**. You can set the Sentry DSN for your project via JDNI, as the SENTRY_DSN environment variable or sentry.dsn system property.
 <appender name="Sentry" class="io.sentry.logback.SentryAppender">
     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
         <level>WARN</level>
     </filter>
 </appender>

 <root level="INFO">
     <appender-ref ref="Sentry"/>
 </root>
  1. Add logging calls to your application. It is usually most effective to add logging.error calls as far towards the top of the stack in your application as possible — good [examples are a main method in a console application] _logback-example/app, or request handler in a web application — to capture as many exceptions as possible. It can also be helpful to log errors as a warning or lower level in other try/catch blocks where checked exceptions are captured.
 public static void main(String[] args)
 {
     try {
         application.run()
     } catch (Exception e) {
         logger.error("Caught exception!", e);
     }
 }
  1. That’s it! Your project should now be reporting Java errors to Sentry. Tell your boss that you deserve a promotion!

We have several other example integrations in our sentry-java-examples repository, and are adding more all the time.

Beyond Log Messages

The Sentry Java SDK also provides additional features that extend beyond simple log messages and tracebacks.

HTTP Request Details

When developing a web application, much of the state that is useful for identifying patterns among exception reports is contained within the attributes of the HTTP request, such as the logged in user account, request URL, headers, and query parameters. If your deployment environment utilizes Java Servlets, these attributes are included automatically on all log messages that occur during the context of a request.

Mapped Diagnostic Context

In addition to HTTP request attributes, it can often be helpful to add additional context to exception reports that are specific to your application. For example, an if you’re running an e-commerce application, it can be helpful to track what step of a checkout process a customer was in when an error occurred. For a consumer product, it can be helpful to track the subscription that the user is a member of so you can effectively triage issues by customer impact. For a stream processing system, it can be helpful to track the component in the processing pipeline where the error occurred.

The SLF4J API provides a feature called the Mapped Diagnostic Context, or MDC, for recording this data. This data is represented as tags or extra data in the Sentry UI. (This feature is available when using the Log4j, Log4j 2, and logback appenders.)

MDC.put("checkout-step", "submit");
try {
    // Any exceptions raised during order submission will include the
    // `checkout-step` tag.
    order.submit();
} finally {
    MDC.remove("checkout-step");
}

In addition to user supplied tags, a few additional tags are included in each event, including the logger, log level, and hostname.

Beyond Log Messages

Asynchronous Logging

A common concern with over-the-network logging is the performance hit incurred from communicating synchronously with a remote server. Asynchronous logging prevents network latency due to logging from directly impacting your application. The SDK design also enables asynchronous logging by frameworks that do not natively support asynchronous appenders. The ability to tune thread pool size, priority, and queue size also allows you to have fine-grained control over how much logging effects your application’s CPU, memory, and latency profile.

Not Just for Java

Although the project is named sentry-java on GitHub, the Sentry Java SDK can be used by any JVM language that provides Java interoperability capabilities, including Clojure, Scala, Kotlin, and Groovy. Because idiomatic Clojure is quite different than the other languages, we offer a sentry-clojure SDK wrapper for a more native experience.

Take a look at the documentation for details on implementing the Sentry SDK. If you’re not yet a Sentry user, you can sign up at any time.

Syntax.fm logo

Listen to the Syntax Podcast

Of course we sponsor a developer podcast. Check it out on your favorite listening platform.

Listen To Syntax