OpenTracing から OpenTelemetry トレーシングへの移行
Quarkus 3.x で、アプリケーションを OpenTracing から OpenTelemetry tracing に移行します。
レガシーの OpenTracing フレームワークは非推奨となり、新しい OpenTelemetry トレーシングフレームワークが採用されました。 OpenTracing の非推奨化を 2022 年 11 月 に発表し、Quarkus コアリポジトリーからエクステンションを削除して、Quarkiverse Hub に移行しました。
まだアプリケーションを OpenTelemetry トレーシングに移行していない場合は、今すぐ移行しましょう。
Quarkus 2.16.x から移行する必要がある場合は、設定プロパティーが異なることに注意してください。 こちら から、古いバージョンの Quarkus OpenTelemetry ガイドを確認する必要があります。
要件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.9
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
概要
デモには 5 つの部分があります。概要を読んでから、ユースケースに最も適したセクションに進んでください。
1 - *開始点*では、OpenTracing を使用するクイックスタートアプリケーションを紹介します。
2 - 最初の部分は、OpenTracing を ビッグバン方式で変更 し、手動の計装が一切ない場合に適しています。
3 - これは、手動でコードを計装した場合の OpenTracing の ビッグバン方式の置換 です。OpenTracing と OpenTelemetry の主な違いを説明しています。
4 - 最後の部分では、OpenTracing シム を使用します。これは、手動で計装されたコードを含む大規模なアプリケーションがある場合に便利です。新しい OpenTelemetry API 上でレガシーの OpenTracing API を使用できるため、移行を段階的に実行するのに役立ちます。
5 - 結論と関連情報
以下に説明するタスクは 3 つのカテゴリーに分類されます。
-
依存関係
-
Configuration (設定)
-
コード
開始点
このチュートリアルは、 opentracing-quickstart
レガシープロジェクトをベースに構築されています。
レガシープロジェクトを生成する
次のコマンドを実行してレガシープロジェクトを作成します。
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=opentracing-quickstart"
このコマンドは Maven プロジェクトを生成し、OpenTracing のサポートとデフォルトの Jaeger
トレーサーを含む smallrye-opentracing
エクステンションをインポートします。
既存のレガシープロジェクトを確認する
便宜上、チュートリアルのすべての手順を含むプロジェクトが github にあります。以下のコマンドでこれをクローンできます。
git clone git@github.com:quarkusio/opentracing-quickstart-migration.git
便宜上、移行するアプリケーションを含む リポジトリー には、このチュートリアルで説明した移行手順を模倣したコミットを含むいくつかのブランチが含まれています。 main
ブランチを確認して、最初から開始できます。
アプリケーション
Quarkus プロジェクトには単一のエンドポイントがあり、関連するクラスは次のようになります。
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello from Quarkus REST";
}
}
生成されたプロジェクトには OpenTracing 固有のコードはありませんが、 smallrye-opentracing
エクステンションが存在し、デフォルトで有効になっているため、コードが自動的にインストルメント化されます。
Jaeger-all-in-one Docker イメージを起動して、キャプチャーされたトレースを取得して確認してみましょう。
docker run -e COLLECTOR_OTLP_ENABLED=true -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 4317:4317 -p 4318:4318 -p 14250:14250 -p 14268:14268 -p 14269:14269 -p 9411:9411 jaegertracing/all-in-one:latest
この時点で、Quarkus 開発モードでアプリケーションを実行できます。
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
/hello
エンドポイント を呼び出すと、関連するトレースを次のアドレスの Jaeger UI で取得できます: http://localhost:16686/
以下のようになります。

OpenTracing から OpenTelemetry へのビッグバン方式の変更
これは最も幸せなパスです。この場合、手動の計装はありません。副次的な影響を受けることなく、OpenTracing から OpenTelemetry へビッグバン方式で変更できます。
依存関係を変更する
2 つのフレームワーク間で移行するには、ビルドファイルで古い quarkus-smallrye-opentracing
エクステンションを削除し、それを quarkus-opentelemetry
エクステンションに置き換える必要があります。
レガシーエクステンションがプロジェクトから削除されます。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-opentracing</artifactId>
</dependency>
implementation("io.quarkus:quarkus-smallrye-opentracing")
新しいものが追加されました。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
implementation("io.quarkus:quarkus-opentelemetry")
Application properties
次の例のように、 application.properties
ファイルから quarkus.jaeger.*
から始まる古い OpenTracing プロパティーを削除する必要があります。
#Legacy OpenTracing properties to be removed
quarkus.jaeger.service-name=legume
quarkus.jaeger.sampler-type=const
quarkus.jaeger.sampler-param=1
quarkus.jaeger.endpoint=http://localhost:14268/api/traces
quarkus.jaeger.log-trace-context=true
OpenTelemetry プロパティーでデフォルト値を使用する場合、 application.properties
ファイルに何かを含める必要はありません。
移行する一般的なプロパティーは次のとおりです。
レガシー OpenTracing プロパティー | 新しい OpenTelemetry プロパティー |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
エクステンションを有効化および無効化する方法は大きく異なります。OpenTelemetry エクステンションはデフォルトで有効になっており、tOpenTelemetry ガイドのこちらのセクション をチェックすることで、エクステンションのすべてまたは一部を無効にすることができます。
すべての OpenTelemetry プロパティーとそのデフォルトについては、OpenTelemetry 設定リファレンス を参照してください。
アプリケーションの実行
Quarkus を再起動する必要はありません。auto-reload が開始され、 /hello
エンドポイント を呼び出して、Jaeger UI でトレースを表示できます: http://localhost:16686/
ただし、OpenTracing ではなく OpenTelemetry の自動計装によって生成されたスパンが表示されるようになりました。

独自の手動計装がない場合は、これで完了です。
手動計装がある場合のビッグバン方式の置換
上記の GreetingResource
クラスの代わりに、もっと複雑なものがあるとします。開始点 からの変更に加えて、追加の作業が必要になります。
このクラスは @Traced
アノテーションを使用し、「手動」のプログラムスパンを作成します。
クイックスタートプロジェクトの GreetingResource
クラスのコードをコピーして貼り付けます。
OpenTracing の手動計装を使用した GreetingsResource
package org.acme;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.opentracing.Traced;
@Path("/hello")
@ApplicationScoped
public class GreetingResource {
@Inject
io.opentracing.Tracer legacyTracer; (1)
@GET
@Produces(MediaType.TEXT_PLAIN)
@Traced(operationName = "Not needed, will change the current span name") (2)
public String hello() {
// Add a tag to the active span
legacyTracer.activeSpan().setTag(Tags.COMPONENT, "GreetingResource"); (3)
// Create a manual inner span
Span innerSpan = legacyTracer.buildSpan("Count response chars").start();
try (Scope dbScope = legacyTracer.scopeManager().activate(innerSpan)) {
String response = "Hello from Quarkus REST";
innerSpan.setTag("response-chars-count", response.length());
return response;
} catch (Exception e) {
innerSpan.setTag("error", true); (4)
innerSpan.setTag("error.message", e.getMessage());
throw e;
} finally {
innerSpan.finish();
}
}
}
1 | レガシーの OpenTracing トレーサーは、新しい OpenTelemetry トレーシングに置き換える必要があります。 |
2 | @Traced アノテーションは @WithSpan アノテーションに置き換えられましたが、この新しいアノテーションは常に新しい Span を作成することに注意してください。JAX-RS エンドポイントはすでに計装されているため、使用しないでください。 |
3 | Tag クラスは Attribute クラスに置き換えられました。 Tags は SemanticAttributes クラスに置き換えられました。これは、属性名を仕様と一貫性のある状態に保つために、可能な限り使用する必要があります。 |
4 | OpenTelemetry でエラーを処理するための新しいメソッドがあります。 |
OpenTelemetry トレーサーは OpenTracing API と互換性がありません。主な変更点を以下の表にまとめています。
注記 | MicroProfile OpenTracing v3 | OpenTelemetry |
---|---|---|
1 |
|
|
2 |
|
|
3 |
Tag |
属性 |
3 |
タグ |
SemanticAttributes |
4 |
|
|
- |
Span 内の SpanContext によって運ばれる Baggage |
Baggage は、OTel コンテキストと並行して伝播される独立した信号であり、その一部ではありません。 |
依存関係が更新されると、クイックスタートプロジェクトが OpenTelemetry で実行されているため、上記のクラスはビルドを中断します。以下のようなエラーがログに表示されます。
2023-10-27 16:11:12,454 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: jakarta.enterprise.inject.spi.DeploymentException: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.opentracing.Tracer and qualifiers [@Default]
...
代わりに新しい OpenTelemetry API を使用する必要があります。これはコードを移行する 1 つの方法です。
OpenTelemetry 手動計装による GreetingsResource
package org.acme;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import static io.opentelemetry.api.trace.StatusCode.*;
@Path("/hello")
@ApplicationScoped
public class GreetingResource {
@Inject
io.opentelemetry.api.trace.Tracer otelTracer;
@GET
@Produces(MediaType.TEXT_PLAIN)
@WithSpan(value = "Not needed, will create a new span, child of the automatic JAX-RS span")
public String hello() {
// Add a tag to the active span
Span incomingSpan = Span.current();
incomingSpan.setAttribute(SemanticAttributes.CODE_NAMESPACE, "GreetingResource");
// Create a manual inner span
Span innerSpan = otelTracer.spanBuilder("Count response chars").startSpan();
try (Scope scope = innerSpan.makeCurrent()) {
final String response = "Hello from Quarkus REST";
innerSpan.setAttribute("response-chars-count", response.length());
return response;
} catch (Exception e) {
innerSpan.setStatus(ERROR);
innerSpan.recordException(e);
throw e;
} finally {
innerSpan.end();
}
}
}
OpenTracing の依存関係をすべて削除すると、コードがビルドされます。トレースに適切なスパンが含まれているか忘れずに再確認してください。これらは Jaeger UI で確認できます: http://localhost:16686/。
OpenTracing シム
このセクションでは、レガシーの OpenTracing API へのアクセスを提供することで移行をスムーズにする OpenTelemetry ライブラリーを紹介します。これは、多くの手動計装ポイントを持つ大規模なアプリケーションの移行に役立ちます。
このセクションを続行するには、コードプロジェクトが 開始点 である必要があります。前のセクションに関連する変更がある場合は、それらを元に戻すか、開始点 の手順に従っ、プロジェクトを再生成してから進めてください。
依存関係
quarkus-smallrye-opentracing
エクステンションを削除し、 quarkus-opentelemetry
エクステンションと opentelemetry-opentracing-shim
ライブラリーをビルドファイルに追加します。
レガシーエクステンションがプロジェクトから削除されます。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-opentracing</artifactId>
</dependency>
implementation("io.quarkus:quarkus-smallrye-opentracing")
新しいものが追加されました。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-opentracing-shim</artifactId>
<!-- No need to declare the version -->
</dependency>
implementation("io.quarkus:quarkus-opentelemetry")
implementation("io.quarkus:opentelemetry-opentracing-shim")
コードの変更
OpenTracing の手動計装を使用した GreetingsResource における `GreetingResource`クラスの初期バージョンを思い出してください:
package org.acme;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.opentracing.Traced;
@Path("/hello")
@ApplicationScoped
public class GreetingResource {
@Inject
io.opentracing.Tracer legacyTracer; (1)
@GET
@Produces(MediaType.TEXT_PLAIN)
@Traced(operationName = "Not needed, will change the current span name") (2)
public String hello() {
// Add a tag to the active span
legacyTracer.activeSpan().setTag(Tags.COMPONENT, "GreetingResource"); (3)
// Create a manual inner span
Span innerSpan = legacyTracer.buildSpan("Count response chars").start();
try (Scope dbScope = legacyTracer.scopeManager().activate(innerSpan)) {
String response = "Hello from Quarkus REST";
innerSpan.setTag("response-chars-count", response.length());
return response;
} catch (Exception e) {
innerSpan.setTag("error", true);
innerSpan.setTag("error.message", e.getMessage());
throw e;
} finally {
innerSpan.finish();
}
}
}
1 | `Tracer`アノテーションを削除し、代わりに OpenTelemetry SDK を注入する必要があります。これは、<3> で必要です。 |
2 | @Traced アノテーションは @WithSpan アノテーションに置き換えられましたが、この新しいアノテーションは常に新しい Span を作成することに注意してください。JAX-RS エンドポイントでは使用しないでください。ここではデモ目的でのみ使用しています。 |
3 | legacyTracer のインスタンスを取得する必要があります。シムには、この目的のためのユーティリティークラスが含まれています: Tracer legacyTracer = OpenTracingShim.createTracerShim(openTelemetry); |
変更後、コードはコンパイルされ、OpenTracing および OpenTelemetry API の両方を同時に使用できるようになります。
package org.acme;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.opentelemetry.opentracingshim.OpenTracingShim;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.tag.Tags;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
@ApplicationScoped
public class GreetingResource {
@Inject
io.opentelemetry.api.OpenTelemetry openTelemetry;
@GET
@Produces(MediaType.TEXT_PLAIN)
@WithSpan(value = "Not needed, will create a new span, child of the automatic JAX-RS span")
public String hello() {
// Add a tag to the active span
Tracer legacyTracer = OpenTracingShim.createTracerShim(openTelemetry);
legacyTracer.activeSpan().setTag(Tags.COMPONENT, "GreetingResource");
// Create a manual inner span
Span innerSpan = legacyTracer.buildSpan("Count response chars").start();
try (Scope dbScope = legacyTracer.scopeManager().activate(innerSpan)) {
String response = "Hello from Quarkus REST";
innerSpan.setTag("response-chars-count", response.length());
return response;
} catch (Exception e) {
innerSpan.setTag("error", true);
innerSpan.setTag("error.message", e.getMessage());
throw e;
} finally {
innerSpan.finish();
}
}
}
シムを永続的な解決策として使用するのではなく、移行をスムーズにするためのツールとしてのみ使用することを推奨します。 |