0
# Metrics and Monitoring
1
2
Built-in application metrics collection, health checks, and operational endpoints for production monitoring and observability.
3
4
## Capabilities
5
6
### Metric Registry
7
8
Central registry for collecting and managing application metrics including timers, counters, meters, histograms, and gauges.
9
10
```java { .api }
11
package com.codahale.metrics;
12
13
public class MetricRegistry {
14
/**
15
* Creates or retrieves a timer metric.
16
*/
17
public Timer timer(String name);
18
19
/**
20
* Creates or retrieves a counter metric.
21
*/
22
public Counter counter(String name);
23
24
/**
25
* Creates or retrieves a meter metric.
26
*/
27
public Meter meter(String name);
28
29
/**
30
* Creates or retrieves a histogram metric.
31
*/
32
public Histogram histogram(String name);
33
34
/**
35
* Registers a gauge metric.
36
*/
37
public <T> Gauge<T> register(String name, Gauge<T> gauge);
38
39
/**
40
* Returns all registered metrics.
41
*/
42
public Map<String, Metric> getMetrics();
43
44
/**
45
* Removes a metric from the registry.
46
*/
47
public boolean remove(String name);
48
}
49
```
50
51
**Usage Example:**
52
53
```java
54
@Override
55
public void run(MyConfiguration configuration, Environment environment) {
56
final MetricRegistry metrics = environment.metrics();
57
58
// Create metrics
59
final Timer requestTimer = metrics.timer("requests");
60
final Counter activeUsers = metrics.counter("active-users");
61
final Meter errorRate = metrics.meter("errors");
62
63
// Register a gauge
64
metrics.register("queue-size", new Gauge<Integer>() {
65
@Override
66
public Integer getValue() {
67
return messageQueue.size();
68
}
69
});
70
}
71
```
72
73
### Metric Annotations
74
75
Annotations for automatically collecting metrics on methods and classes without manual instrumentation.
76
77
```java { .api }
78
package com.codahale.metrics.annotation;
79
80
@Target({ElementType.TYPE, ElementType.METHOD})
81
@Retention(RetentionPolicy.RUNTIME)
82
public @interface Timed {
83
/**
84
* The name of the timer metric.
85
*/
86
String name() default "";
87
88
/**
89
* Whether the timer should be absolute or relative to the class.
90
*/
91
boolean absolute() default false;
92
}
93
94
@Target({ElementType.TYPE, ElementType.METHOD})
95
@Retention(RetentionPolicy.RUNTIME)
96
public @interface Metered {
97
/**
98
* The name of the meter metric.
99
*/
100
String name() default "";
101
102
/**
103
* Whether the meter should be absolute or relative to the class.
104
*/
105
boolean absolute() default false;
106
}
107
108
@Target({ElementType.TYPE, ElementType.METHOD})
109
@Retention(RetentionPolicy.RUNTIME)
110
public @interface Counted {
111
/**
112
* The name of the counter metric.
113
*/
114
String name() default "";
115
116
/**
117
* Whether the counter should be absolute or relative to the class.
118
*/
119
boolean absolute() default false;
120
121
/**
122
* Whether the counter should be monotonic (always incrementing).
123
*/
124
boolean monotonic() default false;
125
}
126
127
@Target({ElementType.TYPE, ElementType.METHOD})
128
@Retention(RetentionPolicy.RUNTIME)
129
public @interface ExceptionMetered {
130
/**
131
* The name of the exception meter metric.
132
*/
133
String name() default "";
134
135
/**
136
* Whether the meter should be absolute or relative to the class.
137
*/
138
boolean absolute() default false;
139
140
/**
141
* The cause of the exception to meter.
142
*/
143
Class<? extends Throwable> cause() default Exception.class;
144
}
145
```
146
147
**Usage Example:**
148
149
```java
150
@Path("/users")
151
public class UserResource {
152
153
@GET
154
@Timed(name = "get-users-timer")
155
@Metered(name = "get-users-requests")
156
public List<User> getUsers() {
157
return userService.findAll();
158
}
159
160
@POST
161
@Timed
162
@ExceptionMetered
163
public User createUser(@Valid User user) {
164
return userService.create(user);
165
}
166
167
@GET
168
@Path("/{id}")
169
@Counted(name = "user-lookups", monotonic = true)
170
public Optional<User> getUser(@PathParam("id") Long id) {
171
return userService.findById(id);
172
}
173
}
174
```
175
176
### Health Checks
177
178
Health check system for monitoring application and dependency health with detailed status reporting.
179
180
```java { .api }
181
package com.codahale.metrics.health;
182
183
public abstract class HealthCheck {
184
/**
185
* Performs the health check and returns the result.
186
*/
187
protected abstract Result check() throws Exception;
188
189
/**
190
* Returns a healthy result with an optional message.
191
*/
192
protected static Result healthy();
193
protected static Result healthy(String message);
194
protected static Result healthy(String message, Object... args);
195
196
/**
197
* Returns an unhealthy result with a message.
198
*/
199
protected static Result unhealthy(String message);
200
protected static Result unhealthy(String message, Object... args);
201
protected static Result unhealthy(Throwable error);
202
203
public static class Result {
204
public boolean isHealthy();
205
public String getMessage();
206
public Throwable getError();
207
}
208
}
209
210
public class HealthCheckRegistry {
211
/**
212
* Registers a health check.
213
*/
214
public void register(String name, HealthCheck healthCheck);
215
216
/**
217
* Runs all registered health checks.
218
*/
219
public Map<String, HealthCheck.Result> runHealthChecks();
220
221
/**
222
* Runs a specific health check.
223
*/
224
public HealthCheck.Result runHealthCheck(String name);
225
}
226
```
227
228
**Usage Example:**
229
230
```java
231
public class DatabaseHealthCheck extends HealthCheck {
232
private final DataSource dataSource;
233
234
public DatabaseHealthCheck(DataSource dataSource) {
235
this.dataSource = dataSource;
236
}
237
238
@Override
239
protected Result check() throws Exception {
240
try (Connection connection = dataSource.getConnection()) {
241
if (connection.isValid(5)) {
242
return Result.healthy("Database connection is valid");
243
} else {
244
return Result.unhealthy("Database connection is invalid");
245
}
246
} catch (SQLException e) {
247
return Result.unhealthy("Cannot connect to database: %s", e.getMessage());
248
}
249
}
250
}
251
252
public class ExternalServiceHealthCheck extends HealthCheck {
253
private final HttpClient httpClient;
254
private final String serviceUrl;
255
256
@Override
257
protected Result check() throws Exception {
258
try {
259
Response response = httpClient.target(serviceUrl + "/health")
260
.request()
261
.get();
262
263
if (response.getStatus() == 200) {
264
return Result.healthy("External service is available");
265
} else {
266
return Result.unhealthy("External service returned status: %d",
267
response.getStatus());
268
}
269
} catch (Exception e) {
270
return Result.unhealthy("External service is unreachable: %s", e.getMessage());
271
}
272
}
273
}
274
275
// Register health checks
276
@Override
277
public void run(MyConfiguration configuration, Environment environment) {
278
environment.healthChecks().register("database",
279
new DatabaseHealthCheck(dataSource));
280
environment.healthChecks().register("external-api",
281
new ExternalServiceHealthCheck(httpClient, apiUrl));
282
}
283
```
284
285
### JVM Metrics
286
287
Built-in JVM metrics for monitoring memory usage, garbage collection, thread pools, and system resources.
288
289
```java { .api }
290
package io.dropwizard.metrics.jvm;
291
292
public class JvmAttributeGaugeSet implements MetricSet {
293
/**
294
* JVM runtime information including name, version, vendor.
295
*/
296
}
297
298
public class MemoryUsageGaugeSet implements MetricSet {
299
/**
300
* Memory usage metrics for heap and non-heap memory.
301
*/
302
}
303
304
public class GarbageCollectorMetricSet implements MetricSet {
305
/**
306
* Garbage collection metrics including count and time.
307
*/
308
}
309
310
public class ThreadStatesGaugeSet implements MetricSet {
311
/**
312
* Thread state metrics including count by state.
313
*/
314
}
315
316
public class ClassLoadingGaugeSet implements MetricSet {
317
/**
318
* Class loading metrics including loaded and unloaded counts.
319
*/
320
}
321
```
322
323
**Usage Example:**
324
325
```java
326
@Override
327
public void run(MyConfiguration configuration, Environment environment) {
328
final MetricRegistry metrics = environment.metrics();
329
330
// Register JVM metrics
331
metrics.registerAll(new JvmAttributeGaugeSet());
332
metrics.registerAll(new MemoryUsageGaugeSet());
333
metrics.registerAll(new GarbageCollectorMetricSet());
334
metrics.registerAll(new ThreadStatesGaugeSet());
335
metrics.registerAll(new ClassLoadingGaugeSet());
336
}
337
```
338
339
### Metrics Reporters
340
341
Built-in reporters for exporting metrics to various monitoring systems and formats.
342
343
```java { .api }
344
package com.codahale.metrics;
345
346
public abstract class ScheduledReporter implements Reporter {
347
/**
348
* Starts the reporter with the given period.
349
*/
350
public void start(long period, TimeUnit unit);
351
352
/**
353
* Stops the reporter.
354
*/
355
public void stop();
356
357
/**
358
* Reports metrics once.
359
*/
360
public void report();
361
362
protected abstract void report(Map<String, Gauge> gauges,
363
Map<String, Counter> counters,
364
Map<String, Histogram> histograms,
365
Map<String, Meter> meters,
366
Map<String, Timer> timers);
367
}
368
369
// Built-in reporters
370
public class ConsoleReporter extends ScheduledReporter {
371
public static Builder forRegistry(MetricRegistry registry);
372
}
373
374
public class CsvReporter extends ScheduledReporter {
375
public static Builder forRegistry(MetricRegistry registry);
376
}
377
378
public class Slf4jReporter extends ScheduledReporter {
379
public static Builder forRegistry(MetricRegistry registry);
380
}
381
```
382
383
**Usage Example:**
384
385
```java
386
@Override
387
public void run(MyConfiguration configuration, Environment environment) {
388
final MetricRegistry metrics = environment.metrics();
389
390
// Console reporter for development
391
final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metrics)
392
.convertRatesTo(TimeUnit.SECONDS)
393
.convertDurationsTo(TimeUnit.MILLISECONDS)
394
.build();
395
consoleReporter.start(1, TimeUnit.MINUTES);
396
397
// CSV reporter for file-based metrics
398
final CsvReporter csvReporter = CsvReporter.forRegistry(metrics)
399
.formatFor(Locale.US)
400
.convertRatesTo(TimeUnit.SECONDS)
401
.convertDurationsTo(TimeUnit.MILLISECONDS)
402
.build(new File("metrics/"));
403
csvReporter.start(30, TimeUnit.SECONDS);
404
405
// SLF4J reporter for log-based metrics
406
final Slf4jReporter slf4jReporter = Slf4jReporter.forRegistry(metrics)
407
.outputTo(LoggerFactory.getLogger("metrics"))
408
.convertRatesTo(TimeUnit.SECONDS)
409
.convertDurationsTo(TimeUnit.MILLISECONDS)
410
.build();
411
slf4jReporter.start(5, TimeUnit.MINUTES);
412
}
413
```
414
415
### Custom Metrics
416
417
Creating custom metrics for application-specific monitoring requirements.
418
419
```java { .api }
420
// Custom gauge for dynamic values
421
public class QueueSizeGauge implements Gauge<Integer> {
422
private final BlockingQueue<?> queue;
423
424
public QueueSizeGauge(BlockingQueue<?> queue) {
425
this.queue = queue;
426
}
427
428
@Override
429
public Integer getValue() {
430
return queue.size();
431
}
432
}
433
434
// Custom health check with dependencies
435
public class CompositeHealthCheck extends HealthCheck {
436
private final List<HealthCheck> dependencies;
437
438
public CompositeHealthCheck(List<HealthCheck> dependencies) {
439
this.dependencies = dependencies;
440
}
441
442
@Override
443
protected Result check() throws Exception {
444
for (HealthCheck dependency : dependencies) {
445
Result result = dependency.execute();
446
if (!result.isHealthy()) {
447
return result;
448
}
449
}
450
return Result.healthy("All dependencies are healthy");
451
}
452
}
453
```
454
455
## Monitoring Endpoints
456
457
### Admin Interface
458
459
Built-in administrative interface providing access to metrics, health checks, and operational commands.
460
461
**Default endpoints:**
462
463
- `/admin/metrics` - JSON metrics output
464
- `/admin/healthcheck` - Health check results
465
- `/admin/ping` - Simple ping endpoint
466
- `/admin/threads` - Thread dump
467
- `/admin/tasks/gc` - Force garbage collection
468
469
**Usage Example:**
470
471
```java
472
@Override
473
public void run(MyConfiguration configuration, Environment environment) {
474
// Custom admin task
475
environment.admin().addTask(new EchoTask());
476
477
// Custom admin servlet
478
environment.admin().addServlet("custom", new CustomAdminServlet())
479
.addMapping("/admin/custom/*");
480
}
481
482
public class EchoTask extends PostBodyTask {
483
public EchoTask() {
484
super("echo");
485
}
486
487
@Override
488
public void execute(Map<String, List<String>> parameters,
489
String body,
490
PrintWriter output) throws Exception {
491
output.println("Echo: " + body);
492
}
493
}
494
```
495
496
### Metrics Configuration
497
498
Configuring metrics collection, reporting, and filtering through application configuration.
499
500
```yaml
501
# Configuration example
502
metrics:
503
frequency: 1 minute
504
reporters:
505
- type: console
506
timeZone: UTC
507
output: stdout
508
- type: csv
509
file: ./metrics/
510
- type: graphite
511
host: localhost
512
port: 2003
513
prefix: myapp
514
jvmMetrics: true
515
```