0
# Metrics and Monitoring
1
2
Comprehensive metrics collection and health monitoring through integration with popular metrics libraries like Codahale Metrics (Dropwizard Metrics), providing detailed insights into connection pool performance, usage patterns, and health status.
3
4
## Capabilities
5
6
### MetricsTracker
7
8
Base class for metrics tracking functionality, providing a framework for collecting and reporting connection pool metrics.
9
10
```java { .api }
11
public class MetricsTracker {
12
/**
13
* No-operation metrics context for disabled metrics.
14
*/
15
public static final MetricsContext NO_CONTEXT;
16
17
/**
18
* Create metrics tracker with pool reference.
19
*
20
* @param pool the BaseHikariPool to track
21
*/
22
public MetricsTracker(BaseHikariPool pool);
23
24
/**
25
* Record a connection request and return timing context.
26
*
27
* @param requestTime timestamp when request was made
28
* @return MetricsContext for timing the request
29
*/
30
public MetricsContext recordConnectionRequest(long requestTime);
31
32
/**
33
* Record connection usage statistics.
34
*
35
* @param bagEntry the PoolBagEntry representing the connection
36
*/
37
public void recordConnectionUsage(PoolBagEntry bagEntry);
38
39
/**
40
* Close the metrics tracker and release resources.
41
*/
42
public void close();
43
}
44
```
45
46
### MetricsContext
47
48
Inner class providing context for timing operations and tracking connection lifecycle events.
49
50
```java { .api }
51
public static class MetricsContext {
52
/**
53
* Stop timing the current operation.
54
*/
55
public void stop();
56
57
/**
58
* Set the last open time for a connection.
59
*
60
* @param bagEntry the PoolBagEntry representing the connection
61
* @param now current timestamp
62
*/
63
public void setConnectionLastOpen(PoolBagEntry bagEntry, long now);
64
}
65
```
66
67
### CodaHaleMetricsTracker
68
69
Integration with Codahale Metrics (Dropwizard Metrics) library, providing detailed timing and histogram metrics for connection pool operations.
70
71
```java { .api }
72
public class CodaHaleMetricsTracker extends MetricsTracker {
73
/**
74
* Create Codahale metrics tracker with registry.
75
* Automatically registers the following metrics:
76
* - Timer: {poolName}.pool.Wait (connection acquisition time)
77
* - Histogram: {poolName}.pool.Usage (connection usage duration)
78
* - Gauge: {poolName}.pool.TotalConnections (total connections in pool)
79
* - Gauge: {poolName}.pool.IdleConnections (idle connections available)
80
* - Gauge: {poolName}.pool.ActiveConnections (active connections in use)
81
* - Gauge: {poolName}.pool.PendingConnections (threads waiting for connections)
82
*
83
* @param pool the BaseHikariPool to track
84
* @param registry the MetricRegistry to register metrics with
85
*/
86
public CodaHaleMetricsTracker(BaseHikariPool pool, MetricRegistry registry);
87
88
/**
89
* Get timer for connection acquisition operations.
90
*
91
* @return Timer measuring connection acquisition time
92
*/
93
public Timer getConnectionAcquisitionTimer();
94
95
/**
96
* Get histogram for connection duration statistics.
97
*
98
* @return Histogram measuring connection usage duration
99
*/
100
public Histogram getConnectionDurationHistogram();
101
}
102
```
103
104
### CodaHaleMetricsTracker.Context
105
106
Codahale-specific metrics context extending base functionality with Timer.Context integration.
107
108
```java { .api }
109
public static final class Context extends MetricsContext {
110
/**
111
* Create context with Codahale Timer for timing operations.
112
*
113
* @param timer Codahale Timer instance
114
*/
115
Context(Timer timer);
116
117
/**
118
* Stop timing and record the measurement.
119
* Overrides base implementation to stop underlying Timer.Context.
120
*/
121
@Override
122
public void stop();
123
124
/**
125
* Set connection last open time for usage tracking.
126
*
127
* @param bagEntry the PoolBagEntry
128
* @param now timestamp when connection was opened
129
*/
130
@Override
131
public void setConnectionLastOpen(PoolBagEntry bagEntry, long now);
132
}
133
```
134
135
### CodahaleHealthChecker
136
137
Health check integration with Codahale HealthCheckRegistry for monitoring connection pool health.
138
139
```java { .api }
140
public class CodahaleHealthChecker {
141
/**
142
* Register health checks for the specified pool with the health check registry.
143
*
144
* @param pool the BaseHikariPool to monitor
145
* @param registry the HealthCheckRegistry to register health checks with
146
*/
147
public static void registerHealthChecks(BaseHikariPool pool, HealthCheckRegistry registry);
148
}
149
```
150
151
## Usage Examples
152
153
### Basic Metrics Configuration
154
155
```java
156
import com.zaxxer.hikari.HikariConfig;
157
import com.zaxxer.hikari.HikariDataSource;
158
import com.codahale.metrics.MetricRegistry;
159
import com.codahale.metrics.health.HealthCheckRegistry;
160
161
// Create metrics registry
162
MetricRegistry metricRegistry = new MetricRegistry();
163
HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
164
165
// Configure HikariCP with metrics
166
HikariConfig config = new HikariConfig();
167
config.setJdbcUrl("jdbc:postgresql://localhost/mydb");
168
config.setUsername("user");
169
config.setPassword("password");
170
config.setPoolName("MonitoredPool");
171
172
// Enable metrics collection
173
config.setMetricRegistry(metricRegistry);
174
config.setHealthCheckRegistry(healthCheckRegistry);
175
176
// Create DataSource with metrics enabled
177
HikariDataSource dataSource = new HikariDataSource(config);
178
```
179
180
### Advanced Metrics Setup with Custom Properties
181
182
```java
183
import com.zaxxer.hikari.HikariConfig;
184
import com.zaxxer.hikari.HikariDataSource;
185
import com.codahale.metrics.MetricRegistry;
186
import com.codahale.metrics.health.HealthCheckRegistry;
187
import java.util.Properties;
188
189
// Create registries
190
MetricRegistry metricRegistry = new MetricRegistry();
191
HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
192
193
// Configure connection pool
194
HikariConfig config = new HikariConfig();
195
config.setJdbcUrl("jdbc:mysql://localhost:3306/myapp");
196
config.setUsername("appuser");
197
config.setPassword("apppass");
198
config.setPoolName("MyAppPool");
199
config.setMaximumPoolSize(20);
200
201
// Configure metrics
202
config.setMetricRegistry(metricRegistry);
203
config.setHealthCheckRegistry(healthCheckRegistry);
204
205
// Configure health check properties
206
Properties healthCheckProps = new Properties();
207
healthCheckProps.setProperty("connectivityCheck", "true");
208
healthCheckProps.setProperty("connectivityCheckTimeoutMs", "1000");
209
healthCheckProps.setProperty("expected99thPercentileMs", "100");
210
config.setHealthCheckProperties(healthCheckProps);
211
212
// Alternative: Add individual health check properties
213
config.addHealthCheckProperty("connectivityCheck", "true");
214
config.addHealthCheckProperty("expected99thPercentileMs", "50");
215
216
HikariDataSource dataSource = new HikariDataSource(config);
217
```
218
219
### Monitoring with Console Reporter
220
221
```java
222
import com.codahale.metrics.ConsoleReporter;
223
import com.codahale.metrics.MetricRegistry;
224
import java.util.concurrent.TimeUnit;
225
226
// Create and configure metrics registry
227
MetricRegistry metricRegistry = new MetricRegistry();
228
229
// Setup HikariCP with metrics (as shown above)
230
HikariConfig config = new HikariConfig();
231
// ... basic configuration
232
config.setMetricRegistry(metricRegistry);
233
config.setPoolName("ConsoleMonitoredPool");
234
235
HikariDataSource dataSource = new HikariDataSource(config);
236
237
// Create console reporter to output metrics
238
ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry)
239
.convertRatesTo(TimeUnit.SECONDS)
240
.convertDurationsTo(TimeUnit.MILLISECONDS)
241
.build();
242
243
// Start reporting every 30 seconds
244
reporter.start(30, TimeUnit.SECONDS);
245
246
// Use the connection pool
247
try (Connection conn = dataSource.getConnection()) {
248
// Database operations - metrics will be collected automatically
249
PreparedStatement stmt = conn.prepareStatement("SELECT COUNT(*) FROM users");
250
ResultSet rs = stmt.executeQuery();
251
// ...
252
}
253
254
// Stop reporting when shutting down
255
reporter.stop();
256
dataSource.close();
257
```
258
259
### JMX Metrics Reporting
260
261
```java
262
import com.codahale.metrics.JmxReporter;
263
import com.codahale.metrics.MetricRegistry;
264
265
// Create metrics registry
266
MetricRegistry metricRegistry = new MetricRegistry();
267
268
// Configure HikariCP with metrics
269
HikariConfig config = new HikariConfig();
270
config.setJdbcUrl("jdbc:h2:mem:testdb");
271
config.setUsername("sa");
272
config.setPassword("");
273
config.setPoolName("JMXMonitoredPool");
274
config.setMetricRegistry(metricRegistry);
275
276
HikariDataSource dataSource = new HikariDataSource(config);
277
278
// Create JMX reporter
279
JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry)
280
.inDomain("com.myapp.hikari.metrics")
281
.build();
282
283
// Start JMX reporting
284
jmxReporter.start();
285
286
// Metrics will now be available via JMX at:
287
// com.myapp.hikari.metrics:name=JMXMonitoredPool.pool.Wait
288
// com.myapp.hikari.metrics:name=JMXMonitoredPool.pool.Usage
289
// com.myapp.hikari.metrics:name=JMXMonitoredPool.pool.TotalConnections
290
// com.myapp.hikari.metrics:name=JMXMonitoredPool.pool.IdleConnections
291
// com.myapp.hikari.metrics:name=JMXMonitoredPool.pool.ActiveConnections
292
// com.myapp.hikari.metrics:name=JMXMonitoredPool.pool.PendingConnections
293
294
// Stop JMX reporting when shutting down
295
jmxReporter.stop();
296
dataSource.close();
297
```
298
299
### Health Check Monitoring
300
301
```java
302
import com.codahale.metrics.health.HealthCheck;
303
import com.codahale.metrics.health.HealthCheckRegistry;
304
import com.zaxxer.hikari.metrics.CodahaleHealthChecker;
305
306
// Create health check registry
307
HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
308
309
// Configure HikariCP with health checks
310
HikariConfig config = new HikariConfig();
311
config.setJdbcUrl("jdbc:postgresql://localhost/mydb");
312
config.setUsername("user");
313
config.setPassword("password");
314
config.setPoolName("HealthMonitoredPool");
315
config.setHealthCheckRegistry(healthCheckRegistry);
316
317
// Configure health check properties
318
config.addHealthCheckProperty("connectivityCheck", "true");
319
config.addHealthCheckProperty("connectivityCheckTimeoutMs", "3000");
320
321
HikariDataSource dataSource = new HikariDataSource(config);
322
323
// Health checks are automatically registered by HikariCP
324
// Check health status programmatically
325
Map<String, HealthCheck.Result> results = healthCheckRegistry.runHealthChecks();
326
327
for (Map.Entry<String, HealthCheck.Result> entry : results.entrySet()) {
328
String healthCheckName = entry.getKey();
329
HealthCheck.Result result = entry.getValue();
330
331
if (result.isHealthy()) {
332
System.out.println(healthCheckName + ": HEALTHY");
333
if (result.getMessage() != null) {
334
System.out.println(" Message: " + result.getMessage());
335
}
336
} else {
337
System.err.println(healthCheckName + ": UNHEALTHY");
338
System.err.println(" Message: " + result.getMessage());
339
if (result.getError() != null) {
340
System.err.println(" Error: " + result.getError().getMessage());
341
}
342
}
343
}
344
```
345
346
### Custom Metrics Collection
347
348
```java
349
import com.codahale.metrics.*;
350
import com.zaxxer.hikari.metrics.CodaHaleMetricsTracker;
351
352
// Access HikariCP's Codahale metrics tracker
353
HikariDataSource dataSource = // ... configured with MetricRegistry
354
355
// Get metrics from the registry by pool name
356
MetricRegistry registry = (MetricRegistry) dataSource.getMetricRegistry();
357
String poolName = dataSource.getPoolName();
358
359
// Connection acquisition timing
360
Timer connectionAcquisitionTimer = registry.getTimer(poolName + ".pool.Wait");
361
System.out.println("Connection Acquisition Stats:");
362
System.out.println(" Count: " + connectionAcquisitionTimer.getCount());
363
System.out.println(" Mean: " + connectionAcquisitionTimer.getSnapshot().getMean() / 1000000 + "ms");
364
System.out.println(" 95th percentile: " + connectionAcquisitionTimer.getSnapshot().get95thPercentile() / 1000000 + "ms");
365
System.out.println(" 99th percentile: " + connectionAcquisitionTimer.getSnapshot().get99thPercentile() / 1000000 + "ms");
366
367
// Connection usage duration
368
Histogram connectionUsageHistogram = registry.getHistogram(poolName + ".pool.Usage");
369
System.out.println("\nConnection Usage Stats:");
370
System.out.println(" Count: " + connectionUsageHistogram.getCount());
371
System.out.println(" Mean duration: " + connectionUsageHistogram.getSnapshot().getMean() / 1000000 + "ms");
372
System.out.println(" Max duration: " + connectionUsageHistogram.getSnapshot().getMax() / 1000000 + "ms");
373
374
// Pool size gauges
375
Gauge<Integer> totalConnections = registry.getGauge(poolName + ".pool.TotalConnections");
376
Gauge<Integer> activeConnections = registry.getGauge(poolName + ".pool.ActiveConnections");
377
Gauge<Integer> idleConnections = registry.getGauge(poolName + ".pool.IdleConnections");
378
Gauge<Integer> pendingConnections = registry.getGauge(poolName + ".pool.PendingConnections");
379
380
System.out.println("\nPool Status:");
381
System.out.println(" Total: " + totalConnections.getValue());
382
System.out.println(" Active: " + activeConnections.getValue());
383
System.out.println(" Idle: " + idleConnections.getValue());
384
System.out.println(" Pending: " + pendingConnections.getValue());
385
```
386
387
### Integration with Monitoring Systems
388
389
#### Prometheus Integration
390
391
```java
392
import io.prometheus.client.CollectorRegistry;
393
import io.prometheus.client.dropwizard.DropwizardExports;
394
import io.prometheus.client.exporter.HTTPServer;
395
396
// Create Dropwizard MetricRegistry
397
MetricRegistry metricRegistry = new MetricRegistry();
398
399
// Configure HikariCP with metrics
400
HikariConfig config = new HikariConfig();
401
// ... basic configuration
402
config.setMetricRegistry(metricRegistry);
403
config.setPoolName("PrometheusPool");
404
405
HikariDataSource dataSource = new HikariDataSource(config);
406
407
// Export Dropwizard metrics to Prometheus
408
CollectorRegistry.defaultRegistry.register(new DropwizardExports(metricRegistry));
409
410
// Start Prometheus HTTP server (optional - for pull-based metrics)
411
HTTPServer server = new HTTPServer(8080);
412
System.out.println("Prometheus metrics available at http://localhost:8080/metrics");
413
414
// Metrics will be available with names like:
415
// hikaricp_PrometheusPool_pool_Wait_seconds
416
// hikaricp_PrometheusPool_pool_Usage_seconds
417
// hikaricp_PrometheusPool_pool_TotalConnections
418
```
419
420
#### Graphite Integration
421
422
```java
423
import com.codahale.metrics.graphite.Graphite;
424
import com.codahale.metrics.graphite.GraphiteReporter;
425
import java.net.InetSocketAddress;
426
import java.util.concurrent.TimeUnit;
427
428
// Create metrics registry
429
MetricRegistry metricRegistry = new MetricRegistry();
430
431
// Configure HikariCP
432
HikariConfig config = new HikariConfig();
433
// ... configuration
434
config.setMetricRegistry(metricRegistry);
435
config.setPoolName("GraphitePool");
436
437
HikariDataSource dataSource = new HikariDataSource(config);
438
439
// Setup Graphite reporter
440
Graphite graphite = new Graphite(new InetSocketAddress("graphite.example.com", 2003));
441
GraphiteReporter reporter = GraphiteReporter.forRegistry(metricRegistry)
442
.prefixedWith("myapp.database.hikaricp")
443
.convertRatesTo(TimeUnit.SECONDS)
444
.convertDurationsTo(TimeUnit.MILLISECONDS)
445
.build(graphite);
446
447
// Start reporting every 10 seconds
448
reporter.start(10, TimeUnit.SECONDS);
449
```
450
451
### Alerting Based on Metrics
452
453
```java
454
import com.codahale.metrics.*;
455
import java.util.concurrent.Executors;
456
import java.util.concurrent.ScheduledExecutorService;
457
import java.util.concurrent.TimeUnit;
458
459
// Setup metrics monitoring and alerting
460
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
461
462
scheduler.scheduleAtFixedRate(() -> {
463
MetricRegistry registry = (MetricRegistry) dataSource.getMetricRegistry();
464
String poolName = dataSource.getPoolName();
465
466
// Monitor connection acquisition time
467
Timer acquisitionTimer = registry.getTimer(poolName + ".pool.Wait");
468
double p99AcquisitionTime = acquisitionTimer.getSnapshot().get99thPercentile() / 1000000.0;
469
470
if (p99AcquisitionTime > 5000) { // Alert if 99th percentile > 5 seconds
471
System.err.println("ALERT: Slow connection acquisition - 99th percentile: " + p99AcquisitionTime + "ms");
472
}
473
474
// Monitor pool utilization
475
Gauge<Integer> totalConnections = registry.getGauge(poolName + ".pool.TotalConnections");
476
Gauge<Integer> activeConnections = registry.getGauge(poolName + ".pool.ActiveConnections");
477
478
if (totalConnections.getValue() > 0) {
479
double utilization = (double) activeConnections.getValue() / totalConnections.getValue();
480
if (utilization > 0.9) { // Alert if utilization > 90%
481
System.err.println("ALERT: High pool utilization: " + String.format("%.1f%%", utilization * 100));
482
}
483
}
484
485
// Monitor pending connections
486
Gauge<Integer> pendingConnections = registry.getGauge(poolName + ".pool.PendingConnections");
487
if (pendingConnections.getValue() > 5) {
488
System.err.println("ALERT: High pending connections: " + pendingConnections.getValue());
489
}
490
491
}, 30, 30, TimeUnit.SECONDS);
492
```