---
title: Datasource MicrometerでSpring BootアプリのJDBC操作を計測する
summary: この記事では、Spring BootでDatasource Micrometerを使いJDBC操作を計測し、SQLログ・トレース・メトリクスをGrafanaで可視化する方法を紹介します。
tags: ["OpenTelemetry", "Spring Boot", "Micrometer", "Java", "Logging", "Tracing", "Metrics", "Loki", "Grafana", "Tempo", "Prometheus"]
categories: ["Programming", "Java", "net", "ttddyy", "observation"]
date: 2026-01-26T05:30:03.578Z
updated: 2026-02-04T01:29:22.737Z
---
> [!NOTE]
> 2026-02-04 datasource-micrometer-opentelemetryの説明を追加。
[Datasource Micrometer](https://github.com/jdbc-observations/datasource-micrometer) ([ドキュメントリンク](https://jdbc-observations.github.io/datasource-micrometer/docs/current/docs/html/)) は、JDBC の Proxy であり、JDBC の操作を Micrometer の [Observation API](https://docs.micrometer.io/micrometer/reference/observation.html) で計測して、Observability を高められます。Trace、Metrics だけでなく、SQL ログやスローログも取得可能です。現在は Micrometer とは独立した開発になっていますが、Micrometer と近い位置で開発されています。
Datasource Micrometer は 2025 年末あたりから [Spring Initializr](https://start.spring.io/) からも選択可能になり、便利に利用できるようになりました。Datasource Micrometer 1 系は Spring Boot 3.5 系で、Datasource Micrometer 2 系は Spring Boot 4 系で利用可能です。

題材アプリとして、簡単な Counter API を作成します。次のコマンドでプロジェクトの雛形を作成します。
```bash
curl -s https://start.spring.io/starter.tgz \
-d artifactId=counter-api\
-d name=counter-api \
-d baseDir=counter-api \
-d packageName=com.example \
-d dependencies=web,jdbc,postgresql,actuator,configuration-processor,opentelemetry,datasource-micrometer,testcontainers \
-d type=maven-project \
-d applicationName=CounterApiApplication | tar -xzvf -
cd counter-api
```
すでに Datasource Micrometer の dependency は設定済みです。`dependencies`に`datasource-micrometer`を含めない場合に比べて、以下の設定が追加されます。
```diff
30a31
> 2.1.0
48a50,57
>
> net.ttddyy.observation
> datasource-micrometer-opentelemetry
>
>
> net.ttddyy.observation
> datasource-micrometer-spring-boot
>
95a105,115
>
>
>
> net.ttddyy.observation
> datasource-micrometer-bom
> ${datasource-micrometer.version}
> pom
> import
>
>
>
```
`dependencies`に`opentelemetry`も含まれる場合は、`datasource-micrometer-opentelemetry`も合わせて追加されます。
せっかくなので [こちらの記事](/entries/892) で紹介した、[OpenTelemetry Logback Appender の AutoConfiguration](https://github.com/making/otel-logs-autoconfigure) も追加します。
```xml
am.ik.spring.opentelemetry
otel-logs-autoconfigure
0.5.0
```
簡単な API を実装します。
```java
cat < src/main/java/com/example/CounterController.java
package com.example;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CounterController {
private final JdbcClient jdbcClient;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public CounterController(JdbcClient jdbcClient) {
this.jdbcClient = jdbcClient;
}
@PostMapping(path = "/counter")
@Transactional
public CounterResponse increment(@RequestBody CounterRequest request) {
CounterResponse counterResponse = this.jdbcClient.sql("""
INSERT INTO counters (entry_id, counter)
VALUES (?, 1)
ON CONFLICT (entry_id)
DO UPDATE
SET counter = counters.counter + 1
RETURNING entry_id, counter
""").param(request.entryId()).query(CounterResponse.class).single();
logger.atInfo()
.addKeyValue("entryId", counterResponse.entryId())
.addKeyValue("counter", counterResponse.counter())
.log("event=increment entryId={} counter={}", counterResponse.entryId(), counterResponse.counter());
return counterResponse;
}
@GetMapping(path = "/counter")
public List getAll() {
return this.jdbcClient.sql("""
SELECT entry_id, counter FROM counters ORDER BY counter DESC
""").query(CounterResponse.class).list();
}
public record CounterRequest(int entryId) {
}
public record CounterResponse(int entryId, long counter) {
}
}
EOF
```
`application.properties` を設定します。Datasource Micrometer による SQL ログとスロークエリログの設定を行います。
```properties
cat <> src/main/resources/application.properties
jdbc.datasource-proxy.json-format=true
jdbc.datasource-proxy.logging=slf4j
jdbc.datasource-proxy.multiline=false
jdbc.datasource-proxy.query.enable-logging=true
jdbc.datasource-proxy.slow-query.enable-logging=true
jdbc.datasource-proxy.slow-query.threshold=5
logging.level.net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener=debug
management.opentelemetry.instrumentation.logback-appender.capture-experimental-attributes=true
management.opentelemetry.instrumentation.logback-appender.capture-key-value-pair-attributes=true
management.otlp.metrics.export.base-time-unit=seconds
management.otlp.metrics.export.step=30s
management.tracing.sampling.probability=1.0
spring.sql.init.mode=always
EOF
```
簡単なスキーマを定義します。
```sql
cat < src/main/resources/schema.sql
CREATE TABLE IF NOT EXISTS counters
(
entry_id BIGINT PRIMARY KEY,
counter BIGINT NOT NULL
);
EOF
```
次のコマンドを実行すると、Testcontainers を使った PostgreSQL と [LGTM スタック](https://hub.docker.com/r/grafana/otel-lgtm) のローカル開発用コンテナが立ち上がります (`src/test/java/com/example/TestcontainersConfiguration.java` を確認してみてください)。DataSource の設定や OTLP エンドポイントの設定は自動で行われます。
```bash
./mvnw spring-boot:test-run
```
起動時に次のようなログが出力され、Grafana の URL がわかります。
```
2026-01-26T13:08:41.512+09:00 INFO 28654 --- [counter-api] [ main] [ ] tc.grafana/otel-lgtm:latest : Creating container for image: grafana/otel-lgtm:latest
2026-01-26T13:08:41.579+09:00 INFO 28654 --- [counter-api] [ main] [ ] tc.grafana/otel-lgtm:latest : Container grafana/otel-lgtm:latest is starting: e0bb34b52593b45152a1236b6766c8ba2b1d3949b5ade2f4126dfbe8bf681790
2026-01-26T13:08:46.762+09:00 INFO 28654 --- [counter-api] [ main] [ ] tc.grafana/otel-lgtm:latest : Container grafana/otel-lgtm:latest started in PT5.249929S
2026-01-26T13:08:46.762+09:00 INFO 28654 --- [counter-api] [ main] [ ] o.t.grafana.LgtmStackContainer : Access to the Grafana dashboard: http://localhost:35507
2026-01-26T13:08:46.862+09:00 INFO 28654 --- [counter-api] [ main] [ ] i.m.c.instrument.push.PushMeterRegistry : Publishing metrics for OtlpMeterRegistry every 30s to http://localhost:35511/v1/metrics with resource attributes {service.name=counter-api}
```
適当にリクエストを送ります。
```bash
curl -s http://localhost:8080/counter --json '{"entryId":100}'
curl -s http://localhost:8080/counter
```
次のような SQL ログを確認できます。
```
2026-01-26T14:11:44.165+09:00 DEBUG 28654 --- [counter-api] [nio-8080-exec-1] [382b35f274086c23f3a45d4c94cfb785-6c507dd2b93e2c20] n.t.d.l.l.SLF4JQueryLoggingListener : {"name":"test", "connection":4, "time":2, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["INSERT INTO counters (entry_id, counter)\nVALUES (?, 1)\nON CONFLICT (entry_id)\nDO UPDATE\n SET counter = counters.counter + 1\nRETURNING entry_id, counter\n"], "params":[["100"]]}
2026-01-26T14:11:44.169+09:00 INFO 28654 --- [counter-api] [nio-8080-exec-1] [382b35f274086c23f3a45d4c94cfb785-25067aeeaad66229] com.example.CounterController : event=increment entryId=100 counter=1
2026-01-26T14:11:45.923+09:00 DEBUG 28654 --- [counter-api] [nio-8080-exec-3] [1a250337750c5fbed850028f8fe5c636-72c7abbd0c14e831] n.t.d.l.l.SLF4JQueryLoggingListener : {"name":"test", "connection":5, "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["SELECT entry_id, counter FROM counters ORDER BY counter DESC\n"], "params":[[]]}
```
次に、以下のコマンドで [`vegeta`](https://github.com/tsenart/vegeta) を使い、負荷をかけてみます。
```bash
for round in $(seq 20); do
echo "=== Round $round/20 ==="
for i in $(seq 3000); do
id=$((RANDOM % 50 + 1))
if [ $((RANDOM % 3)) -eq 0 ]; then
echo '{"method":"GET","url":"http://localhost:8080/counter"}'
else
echo '{"method":"POST","url":"http://localhost:8080/counter","header":{"Content-Type":["application/json"]},"body":"'$(echo -n "{\"entryId\":$id}" | base64)'"}'
fi
done | vegeta attack -rate=100 -duration=30s -format=json | vegeta report
done
```
### Grafanaで確認
Grafana にアクセスします。Grafana の URL はログに出力されています。

#### Traces
左のメニューの Drilldown から **"Traces"** を選択します。

Span Rate の ◇ マーク (Exemplar、代表点) をクリックし、**"View trace"** リンクをクリックします。

そのリクエストの Trace View が表示されます。

**"connection"** Span をクリックすると、commitのタイミング/回数や時間を確認することができます。

**"INSERT ..."** Span をクリックすると、そのタイミングでの SQL を確認することができます。

`datasource-micrometer-opentelemetry`が追加されることにより、Attribute名は [OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/) に準拠するようになりました。
**"Log"** ボタンをクリックしてみます。

この Trace におけるログを確認することができます。

#### Metrics
次に、左のメニューの Drilldown から **"Metrics"** を選択します。**"Prefix filters"** で **"jdbc"** を選択すると、表示を Datasource Micrometer が送信したメトリクスのみに絞ることができます。

取得できるメトリクスは [こちらのドキュメント](https://jdbc-observations.github.io/datasource-micrometer/docs/current/docs/html/#observability-metrics) を参照してください。Connection の開始から終了までの時間、コミット・ロールバックの回数、クエリの実行時間、回数などが取得できます。
#### Logs
最後に、左のメニューの Drilldown から **"Logs"** を選択します。

**"counter-api"** で **"Show logs"** ボタンをクリックします。

特定のログをクリックし、**"Links"** の **"Trace"** ボタンをクリックすると、

また、Trace View に飛ぶことができ、このログに関する SQL などを確認することもできます。

---
Datasource Micrometer を使い、Spring Boot アプリの JDBC 操作を計測する方法を紹介しました。Spring Initializr から利用できるので、簡単に組み込むことができます。ぜひ、使ってみてください。