OpenTelemetry Tracing のデモには、2 つの Spring Boot コンポーネントが含まれています。1 つは Java エージェントを使用しており、最近 v1.x から v2.x にアップグレードしたときに動作が異なることに気付きました。もう 1 つは、GraalVM ネイティブにコンパイルするため、Micrometer Tracing を使用していますが、Java エージェントを処理できません。 私の OpenTelemetry デモ この記事では、Java エージェント v1、Java エージェント v2、Micrometer Tracing の 3 つのアプローチを比較します。 ベースアプリケーションとそのインフラストラクチャ 同じベース アプリケーション、つまり Kotlin でコーディングされたシンプルな Spring Boot アプリケーションを使用します。単一のエンドポイントを提供します。 エンドポイントを超えた関数は という名前です entry() これは という別の関数を呼び出します。 intermediate() 後者は、 の代わりとなる インスタンスを使用して、上記のエンドポイントを呼び出します。 RestTemplate WebClient 無限ループを避けるために、カスタムリクエストヘッダーを渡します。entry 関数がそれを見つけた場合、それ以上先に進みません。 entry() これは次のコードに変換されます。 @SpringBootApplication class Agent1xApplication @RestController class MicrometerController { private val logger = LoggerFactory.getLogger(MicrometerController::class.java) @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") if (done == null) intermediate() } fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } } すべてのセットアップについて、OpenTelemetry が有効になっているプライマリ ステージと、追加の内部スパンを作成するためのカスタマイズ ステージの 2 つのステージを確認します。 マイクロメータトレース Micrometer Tracing は、「ベンダー中立のアプリケーション可観測性ファサード」である から派生したものです。 Micrometer Micrometer Tracing は、最も人気のあるトレーサー ライブラリのシンプルなファサードを提供し、ベンダー ロックインなしで JVM ベースのアプリケーション コードをインストルメント化できるようにします。トレースの収集アクティビティにオーバーヘッドをほとんど追加せず、トレース作業の移植性を最大限に高めるように設計されています。 -- マイクロメータートレースサイト Micrometer Tracing を開始するには、いくつかの依存関係を追加する必要があります。 Spring Boot アクチュエータ、 org.springframework.boot:spring-boot-starter-actuator マイクロメータートレース自体、 io.micrometer:micrometer-tracing ターゲット トレース バックエンド API への「ブリッジ」。私の場合は OpenTelemetry なので、 です。 io.micrometer:micrometer-tracing-bridge-otel バックエンドへの具体的なエクスポーター、 io.opentelemetry:opentelemetry-exporter-otlp バージョンは Spring Boot の親ですでに定義されているため、BOM は必要ありません。 ただし、トレースの送信先とコンポーネントの名前という 2 つのランタイム構成パラメータが必要です。これらは、 変数と 変数によって制御されます。 MANAGEMENT_OTLP_TRACING_ENDPOINT SPRING_APPLICATION_NAME services: jaeger: image: jaegertracing/all-in-one:1.55 environment: - COLLECTOR_OTLP_ENABLED=true #1 ports: - "16686:16686" micrometer-tracing: build: dockerfile: Dockerfile-micrometer environment: MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2 SPRING_APPLICATION_NAME: micrometer-tracing #3 JaegerのOpenTelemetryコレクターを有効にする Jaeger OpenTelemetry gRPC エンドポイントへの完全な URL OpenTelemetryのサービス名を設定する 結果は次のとおりです。 カスタマイズを行わない場合、Micrometer は HTTP リクエストの受信と送信時にスパンを作成します。 フレームワークは、送信のために に魔法を注入する必要があります。そのためには、前者が後者をインスタンス化できるようにする必要があります。 RestClient @SpringBootApplication class MicrometerTracingApplication { @Bean fun restClient(builder: RestClient.Builder) = builder.baseUrl("http://localhost:8080/done").build() } 手動スパンは、OpenTelemetry API 自体を使用する方法など、いくつかの方法で作成できます。ただし、セットアップには多くの定型コードが必要です。最も簡単な方法は、Micrometer の 使用することです。その主な利点は、 と 両方を管理する単一の API を使用できることです。 Observation API を メトリック トレースの 更新されたコードは次のとおりです。 class MicrometerController( private val restClient: RestClient, private val registry: ObservationRegistry ) { @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") val observation = Observation.start("entry", registry) if (done == null) intermediate(observation) observation.stop() } fun intermediate(parent: Observation) { logger.info("intermediate") val observation = Observation.createNotStarted("intermediate", registry) .parentObservation(parent) .start() restClient.get() .header("X-done", "true") .retrieve() .toBodilessEntity() observation.stop() } } 追加された観察呼び出しは、生成されたトレースに反映されます。 オープンテレメトリエージェント v1 Micrometer Tracing の代替として、汎用 があります。その主な利点は、コードにも開発者にも影響を与えないことです。エージェントは、純粋にランタイム スコープの問題です。 OpenTelemetry Java Agent java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar エージェントは、環境変数を使用した OpenTelemetry の構成に従います。 services: agent-1x: build: dockerfile: Dockerfile-agent1 environment: OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1 OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x #2 OTEL_METRICS_EXPORTER: none #3 OTEL_LOGS_EXPORTER: none #4 ports: - "8081:8080" プロトコル、ドメイン、ポートを設定します。ライブラリは を追加します。 /v1/traces OpenTelemetryのサービス名を設定する メトリックもログもエクスポートしない これ以上の設定を行わない場合、次のトレースが得られます。 エージェントは、受信および送信された された関数を自動的に追跡します。トレースは、コール スタックに従って、互いに正しくネストされます。追加の関数をトレースするには、コードベースに依存関係 を追加する必要があります。これで、以前はトレースされていなかった関数に アノテーションを付けることができます。 リクエストと、Spring 関連のアノテーションでマーク io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations @WithSpan 部分はトレースのラベルを制御し、 属性として変換されます。値が空の文字列に設定されている場合 (デフォルト)、関数の名前が出力されます。私の目的には、デフォルト値で十分です。 value() kind span.kind @WithSpan fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } 期待どおりの新しい トレースが生成されます。 intermediate() オープンテレメトリエージェント v2 OpenTelemetry は今年 1 月にエージェントの新しいメジャー バージョンをリリースしました。私はデモをそれに合わせて更新しました。これで、トレースはアプリがリクエストを受信および送信するときにのみ作成されるようになりました。 以前のバージョンと同様に、 アノテーションを使用してトレースを追加できます。唯一の違いは、 関数にもアノテーションを付けなければならないことです。デフォルトではトレースされません。 @WithSpan entry() 議論 Spring が成功した理由は 2 つあります。複雑なソリューション (EJB 2 ) を簡素化し、競合ライブラリに対する抽象化レイヤーを提供したことです。Micrometer Tracing は Zipkin と Jaeger に対する抽象化レイヤーとして始まり、完全に理にかなったものでした。この議論は、OpenTelemetry がプログラミング言語やトレース コレクターのほとんどのライブラリでサポートされているため、意味をなさなくなりました。Observation API は、Metrics と Traces に対して単一の API を使用するため、依然として Micrometer Tracing の大きな利点です。 など Java エージェント側では、OpenTelemetry 構成はすべての技術スタックとライブラリ (環境変数) で同様です。新しいエージェントは Spring に対応していないため、v1 から v2 にアップグレードしたときに少しがっかりしました。Spring アノテーション付き関数はデフォルトではトレースされません。 結局のところ、これは賢明な決断です。表示したくないスパンを削除するよりも、必要なスパンを明示的に指定したほうがはるかに良いのです。 。 ご協力とレビューをいただいた に感謝します Jonatan Ivanov 氏 この投稿の完全なソースコードは GitHub で見つかります: https://github.com/ajavageek/boot-tracing?embedable=true さらに進むには: OpenTelemetry Tracingのデモ マイクロメータトレース OpenTelemetry トレース OpenTelemetry Java 統合 OpenTelemetry Java の例 Spring Boot 3 による分散トレース — Micrometer と OpenTelemetry の比較 Spring Boot 3 による可観測性 2024年8月3日に で最初に公開されました A Java Geek