Skip to content

kiwiproject/dropwizard-application-errors

Repository files navigation

Dropwizard Application Errors

Build Quality Gate Status Coverage CodeQL javadoc License: MIT Maven Central

Dropwizard Application Errors is a library that provides Dropwizard applications with a simple way to record and search on application-level errors.

Installation

Maven:

<dependency>
    <groupId>org.kiwiproject</groupId>
    <artifactId>dropwizard-application-errors</artifactId>
    <version>[version]</version>
</dependency>

Gradle:

implementation group: 'org.kiwiproject', name: 'dropwizard-application-errors', version: '[version]'

Basic Usage

In the run method of your Dropwizard Application class, set up the ApplicationErrorDao.

// Build an error DAO. This one uses an in-memory H2 database.
var serviceDetails = ServiceDetails.from(theHostname, theIpAddress, thePortNumber);
var errorContext = ErrorContextBuilder.newInstance()
        .environment(theDropwizardEnvironment)
        .serviceDetails(serviceDetails)
        .buildInMemoryH2();
ApplicationErrorDao errorDao = errorContext.errorDao();

Then also in your Application#run method, pass the errorDao to other objects (JakartaEE Resources, service classes, etc.):

var weatherResource = new WeatherResource(weatherService, errorDao);
environment.jersey().register(weatherResource);

In classes that want to record application errors, you can use the ApplicationErrorDao to save errors:

import org.kiwiproject.dropwizard.error.model.ApplicationError;

var anError = ApplicationError.builder()
        .description("An error occurred getting weather from service " + weatherService.getName())
        // set other properties
        .build();
errorDao.insertOrIncrementCount(anError);

You can also use any of the convenience factory methods in ApplicationErrors to both log (using an SLF4J Logger) and save the error:

ApplicationErrors.logAndSaveApplicationError(
        errorDao,
        LOG,
        exception, 
        "An error occurred updating getting weather from service {}", weatherService.getName());

Or, you can use ApplicationErrorThrower, which avoids passing the ApplicationErrorDao and Logger to every invocation:

// Store in an instance field, usually in a constructor
this.errorThrower = new ApplicationErrorThrower(errorDao, LOG);

// In methods that want to record application errors
errorThrower.logAndSaveApplicationError(exception,
        "An error occurred updating getting weather from service {}", weatherService.getName());

HTTP Endpoints

By default, the ApplicationErrorResource is registered with Jersey. It provides HTTP endpoints to find and resolve errors.

Health Check

A health check is registered by default, which checks that there aren't any application errors in the last 15 minutes. You can change the time period as necessary.

Testing

This library also provides a JUnit Jupiter extension, ApplicationErrorExtension which ensures the persistent host information is setup correctly for tests. It also provides Mockito test helpers to provide argument matchers and verifications.

UTC Time Zone Requirement

This library currently requires the JVM and database to use UTC as their time zone. Otherwise the timestamp fields createdAt and updatedAt in ApplicationError may not be saved or retrieved correctly from the database.

In addition, some methods in ApplicationErrorDao that accept ZonedDateTime objects may not work as expected, as well as the RecentErrorsHealthCheck.

This requirement for UTC impacts test execution, specifically the JVM running the tests must set the default time zone to UTC. When running via Maven, this is handed transparently by adding -Duser.timezone=UTC to the Maven Surefire plugin. IntelliJ automatically picks this property up when running tests in the IDE as opposed to via Maven, so it works as expected.

Unfortunately, VSCode does not do this when using Language Support for Java(TM) by Red Hat. To fix this, create a workspace setting for the Java test configuration to add this system property to the VM arguments in .vscode/settings.json

{
  "java.test.config": {
    "vmArgs": [
      "-Duser.timezone=UTC"
    ]
  }
}