This version is still in development and is not considered stable yet. For the latest stable version, please use Micrometer 1.16.0!

Database Instrumentation

Micrometer can instrument various libraries that interact with databases:

DataSource Observation Instrumentation

Through the Datasource Micrometer project you can instrument your DataSource to start producing Observations while interacting with the database. That means that depending on your Observation Handler setup you can plug in producing of metrics or distributed tracing.

You can read more about Datasource Micrometer reference documentation here.

DataSource Metrics Instrumentation

// Binding instrumentation through static method
DatabaseTableMetrics.monitor(registry, "foo", "mydb", ds);

// Usage example
try (Connection conn = ds.getConnection()) {
    conn.prepareStatement("CREATE TABLE foo (id int)").execute();
    conn.prepareStatement("INSERT INTO foo VALUES (1)").executeUpdate();
}
assertThat(registry.get("db.table.size").tag("table", "foo").tag("db", "mydb").gauge().value()).isEqualTo(1.0);

jOOQ Instrumentation

// Setting up instrumentation
Configuration configuration = new DefaultConfiguration().set(conn).set(SQLDialect.H2);

MetricsDSLContext jooq = MetricsDSLContext.withMetrics(DSL.using(configuration), meterRegistry, Tags.empty());

// Usage example
jooq.tag("name", "selectAllAuthors").execute("SELECT * FROM author");

assertThat(meterRegistry.get("jooq.query").tag("name", "selectAllAuthors").timer().count()).isEqualTo(1);

Compatibility note for jOOQ versions.

Some newly added jOOQ overloads (for example, DefaultDSLContext#fetchValue(SelectField)) may internally delegate to select(…​). When using builder-level instrumentation with MetricsDSLContext, such delegation can lead to double instrumentation and tag loss on the jooq.query timer.

Recommendations

  • Use only the APIs overridden by MetricsDSLContext for building/executing queries (i.e., prefer methods explicitly overridden by MetricsDSLContext) so each query is timed exactly once with consistent tags. And, avoid relying on newer jOOQ overloads that may delegate to select(…​).

PostgreSQL Instrumentation

// Setting up instrumentation
new PostgreSQLDatabaseMetrics(dataSource, postgres.getDatabaseName()).bindTo(registry);

// Usage example
executeSql("CREATE TABLE gauge_test_table (val varchar(255))",
        "INSERT INTO gauge_test_table (val) VALUES ('foo')", "UPDATE gauge_test_table SET val = 'bar'",
        "SELECT * FROM gauge_test_table", "DELETE FROM gauge_test_table");
Thread.sleep(PGSTAT_STAT_INTERVAL);

final List<String> GAUGES = Arrays.asList(SIZE, CONNECTIONS, ROWS_DEAD, LOCKS);

for (String name : GAUGES) {
    assertThat(get(name).gauge().value()).withFailMessage("Gauge " + name + " is zero.").isGreaterThan(0);
}