or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdhibernate-integration.mdindex.mdjmx-management.mdmetrics-monitoring.mdutilities-advanced.md

metrics-monitoring.mddocs/

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

```