Spring Boot Observability 2026年完全ガイド: OpenTelemetry、分散トレーシング、面接対策
Spring Boot 3.4のObservation API、OpenTelemetryとの連携、分散トレーシングの実装方法を解説。Micrometer TracingとOTLPエクスポートの設定、実践的な面接質問も網羅。

Spring Bootのオブザーバビリティは、ロギング、メトリクス、分散トレーシングを統合し、マイクロサービス全体でリクエストがどのように流れるかを可視化するシステムです。Spring Boot 3以降、フレームワークはMicrometer Tracing(Spring Cloud Sleuthの後継)を採用し、Observation APIを導入しました。このAPIは単一のインスツルメンテーションポイントを提供し、メトリクスとトレースの両方を出力します。
Spring Bootでは、OpenTelemetryを直接呼び出すのではなく、Observation.observe()の使用を推奨しています。1回のインスツルメンテーション呼び出しで、Micrometer経由のメトリクスとOpenTelemetryブリッジ経由のトレースが生成され、コードの重複を減らし、シグナル間でタグ命名の一貫性を確保します。
Observation APIがMicrometerとOpenTelemetryを橋渡しする仕組み
Observation APIは、メトリクスとトレーシングの両方に対するファサードとして機能します。コードがObservation.createNotStarted()を呼び出すと、Spring Bootは観測を登録されたハンドラーにルーティングします。具体的には、Micrometerメトリクス用のMeterObservationHandlerと分散トレース用のTracingObservationHandlerです。このアーキテクチャにより、一度のインスツルメンテーションですべての場所にエクスポートできます。
ブリッジ依存関係micrometer-tracing-bridge-otelは、Micrometer TracingをOpenTelemetryのSDKに接続します。トレースはOpenTelemetryのSdkTracerProviderを通じて流れ、OTLPを介してJaeger、Tempo、または任意のOpenTelemetry互換コレクターにエクスポートされます。
@Configuration
public class ObservabilityConfig {
@Bean
public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
return registry -> registry.observationConfig()
.observationHandler(new ObservationTextPublisher()); // Logs observations to console
}
}上記の設定は、すべての観測をログに記録するObservationHandlerを登録します。本番環境では、自動設定されたハンドラーが追加のコードなしでMicrometerレジストリとOpenTelemetryエクスポーターにデータをプッシュします。
Spring Boot 3.4トレーシングに必要な依存関係
Spring Boot 3.4では、分散トレーシングに明示的な依存関係が必要です。spring-boot-starter-actuatorはObservation APIを提供しますが、トレーシングにはOpenTelemetryブリッジとエクスポーターが必要です。
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>micrometer-tracing-bridge-otelアーティファクトは、Micrometer TracingをOpenTelemetryのAPIに橋渡しします。opentelemetry-exporter-otlpは、HTTPまたはgRPC経由でOTLPプロトコルを使用してコレクターにスパンを送信します。Spring Bootは依存関係管理を通じてバージョンの整合性を管理します。
JaegerまたはTempoへのOTLPエクスポートの設定
OTLP依存関係が存在する場合、Spring BootはOtlpHttpSpanExporterを自動設定します。エクスポーターはapplication.ymlで指定されたエンドポイントにトレースを送信します。
# application.yml
management:
tracing:
sampling:
probability: 1.0 # 100% sampling for dev, reduce in production
otlp:
tracing:
endpoint: http://localhost:4318/v1/traces
opentelemetry:
resource-attributes:
service.name: order-service
deployment.environment: stagingresource-attributesは、すべてのスパンにメタデータを付与します。Grafana TempoやJaegerなどのバックエンドは、これらの属性を使用してサービスと環境ごとにトレースをグループ化します。開発中はsampling.probabilityを1.0に設定してすべてのリクエストをキャプチャしますが、本番システムでは通常、ストレージコストを制御するために1%から10%の間でサンプリングします。
低カーディナリティと高カーディナリティタグによるカスタム観測の作成
観測は2種類のタグをサポートします。メトリクス用の低カーディナリティ(HTTPメソッドやステータスコードなどの有限値)とトレース用の高カーディナリティ(ユーザーIDやリクエストIDなどの無制限値)です。
@Service
public class PaymentService {
private final ObservationRegistry observationRegistry;
public PaymentService(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
public PaymentResult processPayment(PaymentRequest request) {
return Observation.createNotStarted("payment.process", observationRegistry)
.lowCardinalityKeyValue("payment.method", request.getMethod().name()) // enum: CARD, BANK_TRANSFER
.lowCardinalityKeyValue("currency", request.getCurrency()) // bounded: USD, EUR, GBP
.highCardinalityKeyValue("payment.id", request.getPaymentId()) // unique per request
.highCardinalityKeyValue("customer.id", request.getCustomerId()) // high cardinality
.observe(() -> executePayment(request));
}
private PaymentResult executePayment(PaymentRequest request) {
// Payment gateway call
return new PaymentResult(true, "TXN-" + UUID.randomUUID());
}
}低カーディナリティタグはメトリクスとトレースの両方に表示されます。高カーディナリティタグはトレースにのみ表示されます。これは、無制限のディメンションを持つメトリクスがストレージを爆発的に増加させるためです。この区別により、トレースの詳細を豊富に保ちながら、Prometheusのカーディナリティ爆発を防ぎます。
面接官は、特定のタグをメトリクスから除外すべき理由をよく質問します。答えはカーディナリティに関連しています。メトリクスのユーザーIDタグは、ユーザーごとに1つの時系列を作成し、潜在的に数百万の時系列になる可能性があります。監視バックエンドは高カーディナリティに苦労し、メモリ枯渇やクエリの遅延を引き起こします。トレースはサンプリングを通じて高カーディナリティを処理するため、リクエスト固有の識別子を配置する正しい場所です。
Spring Bootの面接対策はできていますか?
インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。
非同期境界を越えたトレースコンテキストの伝播
分散トレーシングにはコンテキスト伝播が必要です。HTTPヘッダーはサービス間でトレースIDを運びますが、@AsyncメソッドやCompletableFutureチェーンなどの非同期操作は、設定されていない場合コンテキストを失う可能性があります。
Spring Boot 3.4は、設定時にリアクティブストリームと@Asyncメソッドの自動伝播を提供します:
# application.yml
spring:
reactor:
context-propagation: auto
task:
execution:
propagate-context: trueカスタムTaskExecutorビーンの場合は、ContextPropagatingTaskDecoratorでラップします:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
executor.initialize();
return executor;
}
}デコレーターは、現在のObservationとトレースコンテキストを非同期スレッドにコピーします。これがないと、非同期タスクで開始されたスパンには親がなく、トレースツリーが壊れます。
@Observedと@NewSpanアノテーションの使用
Spring Boot 3.4は、アノテーションによる宣言的オブザーバビリティをサポートしています。AspectJウィーバーを追加してアノテーション処理を有効にします:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency># application.yml
management:
observations:
annotations:
enabled: true@Service
public class InventoryService {
@Observed(name = "inventory.check", contextualName = "checkStock")
public StockLevel checkStock(String productId) {
// Database query
return new StockLevel(productId, 42);
}
@NewSpan("inventory.reserve") // Creates a child span under the current trace
public ReservationResult reserveStock(String productId, int quantity) {
// Update inventory
return new ReservationResult(true, "RES-" + System.currentTimeMillis());
}
}@Observedはメトリクス(タイマー)とスパンの両方を作成します。@NewSpanはスパンのみを作成し、操作が他の場所でメトリクスを持っている場合に便利です。両方のアノテーションは、例外記録とスパンステータスを自動的に処理します。
Spring Boot 3.4の自動インスツルメンテーションコンポーネント
Spring Boot 3.4は、コード変更なしで複数のコンポーネントを自動インスツルメントします:
| コンポーネント | 観測名 | キャプチャ内容 |
|---|---|---|
| Spring MVC | http.server.requests | リクエストパス、メソッド、ステータス、例外 |
| WebClient | http.client.requests | アウトバウンドHTTPコール |
| RestClient | http.client.requests | アウトバウンドHTTPコール(Spring 6.1+) |
| Spring Kafka | spring.kafka.listener | コンシューマーグループ、トピック、パーティション |
| Spring Data JPA | spring.data.repository | リポジトリメソッド、クエリ時間 |
| Scheduled Tasks | spring.scheduling | タスク名、実行時間 |
Spring Boot Actuatorドキュメントには、すべての自動インスツルメントコンポーネントが一覧されています。Datasource Micrometerなどのサードパーティライブラリは、JDBCクエリトレーシングを追加します。
ノイズを減らすための観測フィルタリング
ヘルスチェック、レディネスプローブ、静的リソースはトレースにノイズを生成します。述語を使用してそれらをフィルタリングします:
@Configuration
public class ObservationFilterConfig {
@Bean
public ObservationPredicate noHealthChecks() {
return (name, context) -> !name.equals("http.server.requests")
|| !isHealthEndpoint(context);
}
private boolean isHealthEndpoint(Observation.Context context) {
if (context instanceof ServerRequestObservationContext http) {
String path = http.getCarrier().getRequestURI();
return path.startsWith("/actuator/health") || path.startsWith("/actuator/ready");
}
return false;
}
}または、設定で名前によって観測を無効にします:
# application.yml
management:
observations:
enable:
spring.security: false # Disable Spring Security observations
http.server.requests.actuator: false # Custom predicate nameサンプリングは、すべてのエンドポイントで収集されるトレースの割合を減らします。フィルタリングは、特定のエンドポイントを完全に削除します。診断価値を提供しないエンドポイント(ヘルスチェック、メトリクススクレイピング)にはフィルタリングを使用します。代表的なデータを保持しながらコストを制御するにはサンプリングを使用します。
トレースIDとログの相関付け
Micrometer Tracingがアクティブな場合、Spring Boot 3.4はトレースIDとスパンIDをMDC(Mapped Diagnostic Context)に自動的に追加します。LogbackとLog4j2は、ログ出力にこれらのIDを含めることができます:
<!-- logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId=%X{traceId} spanId=%X{spanId} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>このパターンにより、すべてのログ行にトレースIDが含まれます。トレースIDでログを検索すると、すべてのサービスにわたる単一のリクエストからのすべてのメッセージが返され、JaegerまたはTempoのスパンとログが相関付けられます。
Spring Bootオブザーバビリティに関する一般的な面接質問
面接官は、オブザーバビリティに関する概念的理解と実務経験の両方を評価します。これらの質問は、シニアバックエンドロールで頻繁に登場します。
Q: Micrometer TracingとOpenTelemetryの違いは何ですか?
Micrometer Tracingは、分散トレーシングのためのベンダー中立的なAPIであり、Micrometerがメトリクスを抽象化するのと同様です。OpenTelemetryは特定の実装とプロトコルです。Spring BootはAPIとしてMicrometer Tracingを使用し、micrometer-tracing-bridge-otelを介してエクスポート用にOpenTelemetryにブリッジします。このレイヤリングにより、アプリケーションはコード変更なしでバックエンドを切り替えることができます。
Q: なぜSpringは直接OpenTelemetryインスツルメンテーションよりもObservation APIを推奨するのですか?
Observation APIは、メトリクスとトレースの両方を出力する単一のインスツルメンテーションポイントを提供します。直接OpenTelemetry呼び出しはトレースのみを生成します。Observation.observe()を使用すると、同じコードからタイマーメトリクスとスパンが生成され、重複を減らし、一貫した命名を確保します。
Q: スパン間にギャップがあるトレースをデバッグするにはどうすればよいですか?
ギャップは、インスツルメンテーションの欠落またはコンテキスト伝播の中断を示しています。コードがContextPropagatingTaskDecoratorなしで非同期操作を使用しているかどうかを確認します。HTTPクライアント(WebClient、RestClient、または手動でラップされたRestTemplate)がインスツルメントされていることを確認します。メッセージキューの場合、トレースヘッダーがメッセージプロパティを通じて伝播されることを確認します。
Q: 高カーディナリティタグをメトリクスに追加するとどうなりますか?
各一意のタグ値は新しい時系列を作成します。数百万のユーザーを持つユーザーIDタグは数百万の時系列を作成し、Prometheusまたは他のTSDBバックエンドのメモリを枯渇させます。修正は、lowCardinalityKeyValue()ではなくhighCardinalityKeyValue()を使用することで、高カーディナリティが期待されるトレースにのみタグを追加します。
Docker Composeを使用した分散トレーシングパイプラインの構築
ローカルのオブザーバビリティスタックは、本番環境にデプロイする前にインスツルメンテーションを検証するのに役立ちます。この例では、OpenTelemetry CollectorとJaegerを使用します:
# docker-compose.yml
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:0.102.0
command: ["--config", "/etc/otel-collector-config.yml"]
volumes:
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
- "4318:4318" # OTLP HTTP
- "4317:4317" # OTLP gRPC
jaeger:
image: jaegertracing/jaeger:2.3
ports:
- "16686:16686" # UI
environment:
- COLLECTOR_OTLP_ENABLED=true
app:
build: .
environment:
- MANAGEMENT_OTLP_TRACING_ENDPOINT=http://otel-collector:4318/v1/traces
depends_on:
- otel-collector# otel-collector-config.yml
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/jaeger]コレクターはSpring Bootアプリケーションからスパンを受信し、Jaegerに転送します。このアーキテクチャにより、アプリケーションコードを変更せずにエクスポーター(Tempo、Zipkin、クラウドバックエンド)を追加できます。
今すぐ練習を始めましょう!
面接シミュレーターと技術テストで知識をテストしましょう。
Spring Bootオブザーバビリティの重要ポイント
- Observation APIはメトリクスとトレーシングを統合します。1回の
Observation.observe()呼び出しでタイマーメトリクスとスパンの両方が生成され、二重インスツルメンテーションが不要になります。 - OTLPエクスポートを有効にするには、
micrometer-tracing-bridge-otelとopentelemetry-exporter-otlpを追加します。Spring Boot 3.4は、management.otlp.tracing.endpointのエンドポイントでHTTPエクスポーターを自動設定します。 - メトリクスに表示されるディメンション(有限値)には
lowCardinalityKeyValue()を使用します。トレースのみのデータ(ユーザーID、リクエストID)にはhighCardinalityKeyValue()を使用します。 spring.task.execution.propagate-context=trueで非同期コードのコンテキスト伝播を有効にし、カスタムエクスキューターをContextPropagatingTaskDecoratorでラップします。ObservationPredicateビーンを使用して/actuator/healthなどのノイズの多いエンドポイントをフィルタリングし、トレースをビジネス操作に集中させます。- ログパターンには、分散トレースとログ行を相関付けるために
%X{traceId}を含めます。 - オブザーバビリティに関する面接質問は、カーディナリティ、コンテキスト伝播の失敗、Observation APIと直接OpenTelemetry使用の区別に焦点を当てています。
Spring Boot のバグを見つけられますか
実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

執筆
Anthony Fillion-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年9月19日 更新
共有
関連記事

Spring Boot YAML vs Properties:設定ファイル比較と面接質問 2026年版
Spring BootのYAMLとPropertiesファイルの違いを徹底比較。application.ymlとapplication.propertiesの使い分け、ベストプラクティス、面接対策を解説します。

2026年のSpring Boot構造化ロギング:LogbackとOpenTelemetryによる本番JSON出力
Spring Boot 4.xの構造化ロギング完全ガイドです。ネイティブJSON出力、OpenTelemetry Starter、MDCトレーシング、本番オブザーバビリティのためのELK Stack連携を解説します。

Spring Kafka: 耐障害性のあるコンシューマによるイベント駆動アーキテクチャ
イベント駆動アーキテクチャ向けの完全なSpring Kafkaガイド。設定、耐障害性のあるコンシューマ、リトライポリシー、Dead Letter Queue、分散アプリケーション向けの本番パターン。