Logback

The sentry-logback library provides Logback support for Sentry via an Appender that sends logged exceptions to Sentry. Once this integration is configured you can also use Sentry’s static API, as shown on the usage page, in order to do things like record breadcrumbs, set the current user, or manually send events.

The source can be found on GitHub.

Installation

Copied
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-logback</artifactId>
    <version>1.7.30</version>
</dependency>

For other dependency managers see the central Maven repository.

Usage

The following example configures a ConsoleAppender that logs to standard out at the INFO level and a SentryAppender that logs to the Sentry server at the WARN level. The ConsoleAppender is only provided as an example of a non-Sentry appender that is set to a different logging threshold, like one you may already have in your project.

Example configuration using the logback.xml format:

Copied
<configuration>
    <!-- Configure the Console appender -->
    <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>

    <!-- Configure the Sentry appender, overriding the logging threshold to the WARN level -->
    <appender name="Sentry" class="io.sentry.logback.SentryAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
        <!-- Optionally add an encoder -->
        <encoder>
           <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </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>

Next, you’ll need to configure your DSN (client key) and optionally other values such as environment and release. See the configuration page for ways you can do this.

Additional Data

It’s possible to add extra data to events thanks to the MDC system provided by Logback.

Mapped Tags

By default all MDC parameters are stored under the “Additional Data” tab in Sentry. By specifying the mdctags option in your configuration you can choose which MDC keys to send as tags instead, which allows them to be used as filters within the Sentry UI.

Copied
void logWithExtras() {
    // MDC extras
    MDC.put("Environment", "Development");
    MDC.put("OS", "Linux");

    // This sends an event where the Environment and OS MDC values are set as additional data
    logger.error("This is a test");
}

Global Tags

Sometimes it's useful to add tags and extra data to all log events. You can add tags and extras to logs globally (not thread-bound) by adding entries to the LoggerContext. Tags are distinguished by the existing mdcTags configuration property detailed above.

Copied
  LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
  context.putProperty("global", "value");

Global log entries can also be added via third-party encoders (whether such entries can be distinguished as tags or entries, however, is encoder implementation-specific). The net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder for example has a customFields option:

Copied
  <encoder class="net.logstash.logback.encoder.LogstashEncoder">
    <customFields>{"appname":"myWebservice","roles":["customerorder","auth"]}</customFields>
  </encoder>

In the event of naming clashes, the more specific MDC tags will take precedence.

In Practice

Copied
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.MarkerFactory;

public class MyClass {
    private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
    private static final Marker MARKER = MarkerFactory.getMarker("myMarker");

    void logSimpleMessage() {
        // This sends a simple event to Sentry
        logger.error("This is a test");
    }

    void logWithBreadcrumbs() {
        // Record a breadcrumb that will be sent with the next event(s),
        // by default the last 100 breadcrumbs are kept.
        Sentry.record(
            new BreadcrumbBuilder().setMessage("User made an action").build()
        );

        // This sends a simple event to Sentry
        logger.error("This is a test");
    }

    void logWithTag() {
        // This sends an event with a tag named 'logback-Marker' to Sentry
        logger.error(MARKER, "This is a test");
    }

    void logWithExtras() {
        // MDC extras
        MDC.put("extra_key", "extra_value");
        // This sends an event with extra data to Sentry
        logger.error("This is a test");
    }

    void logWithGlobalTag() {
       LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
       // This adds a tag named 'logback-Marker' to every subsequent Sentry event
       context.putProperty(MARKER, "This is a test");

        // This sends an event to Sentry, and a tag named 'logback-Marker' will be added.
        logger.info("This is a test");
    }

    void addGlobalExtras() {
       LoggerContext context = (LoggerContext)LoggerFactory.getILoggerFactory();
       // This adds extra data to every subsequent Sentry event
       context.putProperty("extra_key", "extra_value");

       // This sends an event to Sentry, and extra data ("extra_key", "extra_value") will be added.
        logger.info("This is a test");
    }

    void logException() {
        try {
            unsafeMethod();
        } catch (Exception e) {
            // This sends an exception event to Sentry
            logger.error("Exception caught", e);
        }
    }

    void unsafeMethod() {
        throw new UnsupportedOperationException("You shouldn't call this!");
    }
}
You can edit this page on GitHub.