Dropwizard Application Errors is a library that provides Dropwizard applications with a simple way to record and search on application-level errors.
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]'
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());
By default, the ApplicationErrorResource
is registered with Jersey.
It provides HTTP endpoints to find and resolve errors.
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.
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.
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"
]
}
}