Java framework for developing ops-friendly, high-performance, RESTful web applications
—
Built-in application metrics collection, health checks, and operational endpoints for production monitoring and observability.
Central registry for collecting and managing application metrics including timers, counters, meters, histograms, and gauges.
package com.codahale.metrics;
public class MetricRegistry {
/**
* Creates or retrieves a timer metric.
*/
public Timer timer(String name);
/**
* Creates or retrieves a counter metric.
*/
public Counter counter(String name);
/**
* Creates or retrieves a meter metric.
*/
public Meter meter(String name);
/**
* Creates or retrieves a histogram metric.
*/
public Histogram histogram(String name);
/**
* Registers a gauge metric.
*/
public <T> Gauge<T> register(String name, Gauge<T> gauge);
/**
* Returns all registered metrics.
*/
public Map<String, Metric> getMetrics();
/**
* Removes a metric from the registry.
*/
public boolean remove(String name);
}Usage Example:
@Override
public void run(MyConfiguration configuration, Environment environment) {
final MetricRegistry metrics = environment.metrics();
// Create metrics
final Timer requestTimer = metrics.timer("requests");
final Counter activeUsers = metrics.counter("active-users");
final Meter errorRate = metrics.meter("errors");
// Register a gauge
metrics.register("queue-size", new Gauge<Integer>() {
@Override
public Integer getValue() {
return messageQueue.size();
}
});
}Annotations for automatically collecting metrics on methods and classes without manual instrumentation.
package com.codahale.metrics.annotation;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Timed {
/**
* The name of the timer metric.
*/
String name() default "";
/**
* Whether the timer should be absolute or relative to the class.
*/
boolean absolute() default false;
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Metered {
/**
* The name of the meter metric.
*/
String name() default "";
/**
* Whether the meter should be absolute or relative to the class.
*/
boolean absolute() default false;
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Counted {
/**
* The name of the counter metric.
*/
String name() default "";
/**
* Whether the counter should be absolute or relative to the class.
*/
boolean absolute() default false;
/**
* Whether the counter should be monotonic (always incrementing).
*/
boolean monotonic() default false;
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionMetered {
/**
* The name of the exception meter metric.
*/
String name() default "";
/**
* Whether the meter should be absolute or relative to the class.
*/
boolean absolute() default false;
/**
* The cause of the exception to meter.
*/
Class<? extends Throwable> cause() default Exception.class;
}Usage Example:
@Path("/users")
public class UserResource {
@GET
@Timed(name = "get-users-timer")
@Metered(name = "get-users-requests")
public List<User> getUsers() {
return userService.findAll();
}
@POST
@Timed
@ExceptionMetered
public User createUser(@Valid User user) {
return userService.create(user);
}
@GET
@Path("/{id}")
@Counted(name = "user-lookups", monotonic = true)
public Optional<User> getUser(@PathParam("id") Long id) {
return userService.findById(id);
}
}Health check system for monitoring application and dependency health with detailed status reporting.
package com.codahale.metrics.health;
public abstract class HealthCheck {
/**
* Performs the health check and returns the result.
*/
protected abstract Result check() throws Exception;
/**
* Returns a healthy result with an optional message.
*/
protected static Result healthy();
protected static Result healthy(String message);
protected static Result healthy(String message, Object... args);
/**
* Returns an unhealthy result with a message.
*/
protected static Result unhealthy(String message);
protected static Result unhealthy(String message, Object... args);
protected static Result unhealthy(Throwable error);
public static class Result {
public boolean isHealthy();
public String getMessage();
public Throwable getError();
}
}
public class HealthCheckRegistry {
/**
* Registers a health check.
*/
public void register(String name, HealthCheck healthCheck);
/**
* Runs all registered health checks.
*/
public Map<String, HealthCheck.Result> runHealthChecks();
/**
* Runs a specific health check.
*/
public HealthCheck.Result runHealthCheck(String name);
}Usage Example:
public class DatabaseHealthCheck extends HealthCheck {
private final DataSource dataSource;
public DatabaseHealthCheck(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
protected Result check() throws Exception {
try (Connection connection = dataSource.getConnection()) {
if (connection.isValid(5)) {
return Result.healthy("Database connection is valid");
} else {
return Result.unhealthy("Database connection is invalid");
}
} catch (SQLException e) {
return Result.unhealthy("Cannot connect to database: %s", e.getMessage());
}
}
}
public class ExternalServiceHealthCheck extends HealthCheck {
private final HttpClient httpClient;
private final String serviceUrl;
@Override
protected Result check() throws Exception {
try {
Response response = httpClient.target(serviceUrl + "/health")
.request()
.get();
if (response.getStatus() == 200) {
return Result.healthy("External service is available");
} else {
return Result.unhealthy("External service returned status: %d",
response.getStatus());
}
} catch (Exception e) {
return Result.unhealthy("External service is unreachable: %s", e.getMessage());
}
}
}
// Register health checks
@Override
public void run(MyConfiguration configuration, Environment environment) {
environment.healthChecks().register("database",
new DatabaseHealthCheck(dataSource));
environment.healthChecks().register("external-api",
new ExternalServiceHealthCheck(httpClient, apiUrl));
}Built-in JVM metrics for monitoring memory usage, garbage collection, thread pools, and system resources.
package io.dropwizard.metrics.jvm;
public class JvmAttributeGaugeSet implements MetricSet {
/**
* JVM runtime information including name, version, vendor.
*/
}
public class MemoryUsageGaugeSet implements MetricSet {
/**
* Memory usage metrics for heap and non-heap memory.
*/
}
public class GarbageCollectorMetricSet implements MetricSet {
/**
* Garbage collection metrics including count and time.
*/
}
public class ThreadStatesGaugeSet implements MetricSet {
/**
* Thread state metrics including count by state.
*/
}
public class ClassLoadingGaugeSet implements MetricSet {
/**
* Class loading metrics including loaded and unloaded counts.
*/
}Usage Example:
@Override
public void run(MyConfiguration configuration, Environment environment) {
final MetricRegistry metrics = environment.metrics();
// Register JVM metrics
metrics.registerAll(new JvmAttributeGaugeSet());
metrics.registerAll(new MemoryUsageGaugeSet());
metrics.registerAll(new GarbageCollectorMetricSet());
metrics.registerAll(new ThreadStatesGaugeSet());
metrics.registerAll(new ClassLoadingGaugeSet());
}Built-in reporters for exporting metrics to various monitoring systems and formats.
package com.codahale.metrics;
public abstract class ScheduledReporter implements Reporter {
/**
* Starts the reporter with the given period.
*/
public void start(long period, TimeUnit unit);
/**
* Stops the reporter.
*/
public void stop();
/**
* Reports metrics once.
*/
public void report();
protected abstract void report(Map<String, Gauge> gauges,
Map<String, Counter> counters,
Map<String, Histogram> histograms,
Map<String, Meter> meters,
Map<String, Timer> timers);
}
// Built-in reporters
public class ConsoleReporter extends ScheduledReporter {
public static Builder forRegistry(MetricRegistry registry);
}
public class CsvReporter extends ScheduledReporter {
public static Builder forRegistry(MetricRegistry registry);
}
public class Slf4jReporter extends ScheduledReporter {
public static Builder forRegistry(MetricRegistry registry);
}Usage Example:
@Override
public void run(MyConfiguration configuration, Environment environment) {
final MetricRegistry metrics = environment.metrics();
// Console reporter for development
final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metrics)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
consoleReporter.start(1, TimeUnit.MINUTES);
// CSV reporter for file-based metrics
final CsvReporter csvReporter = CsvReporter.forRegistry(metrics)
.formatFor(Locale.US)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build(new File("metrics/"));
csvReporter.start(30, TimeUnit.SECONDS);
// SLF4J reporter for log-based metrics
final Slf4jReporter slf4jReporter = Slf4jReporter.forRegistry(metrics)
.outputTo(LoggerFactory.getLogger("metrics"))
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
slf4jReporter.start(5, TimeUnit.MINUTES);
}Creating custom metrics for application-specific monitoring requirements.
// Custom gauge for dynamic values
public class QueueSizeGauge implements Gauge<Integer> {
private final BlockingQueue<?> queue;
public QueueSizeGauge(BlockingQueue<?> queue) {
this.queue = queue;
}
@Override
public Integer getValue() {
return queue.size();
}
}
// Custom health check with dependencies
public class CompositeHealthCheck extends HealthCheck {
private final List<HealthCheck> dependencies;
public CompositeHealthCheck(List<HealthCheck> dependencies) {
this.dependencies = dependencies;
}
@Override
protected Result check() throws Exception {
for (HealthCheck dependency : dependencies) {
Result result = dependency.execute();
if (!result.isHealthy()) {
return result;
}
}
return Result.healthy("All dependencies are healthy");
}
}Built-in administrative interface providing access to metrics, health checks, and operational commands.
Default endpoints:
/admin/metrics - JSON metrics output/admin/healthcheck - Health check results/admin/ping - Simple ping endpoint/admin/threads - Thread dump/admin/tasks/gc - Force garbage collectionUsage Example:
@Override
public void run(MyConfiguration configuration, Environment environment) {
// Custom admin task
environment.admin().addTask(new EchoTask());
// Custom admin servlet
environment.admin().addServlet("custom", new CustomAdminServlet())
.addMapping("/admin/custom/*");
}
public class EchoTask extends PostBodyTask {
public EchoTask() {
super("echo");
}
@Override
public void execute(Map<String, List<String>> parameters,
String body,
PrintWriter output) throws Exception {
output.println("Echo: " + body);
}
}Configuring metrics collection, reporting, and filtering through application configuration.
# Configuration example
metrics:
frequency: 1 minute
reporters:
- type: console
timeZone: UTC
output: stdout
- type: csv
file: ./metrics/
- type: graphite
host: localhost
port: 2003
prefix: myapp
jvmMetrics: trueInstall with Tessl CLI
npx tessl i tessl/maven-io-dropwizard--dropwizard-project