OpenTelemetryの使用
このガイドでは、Quarkusアプリケーションが OpenTelemetryを利用して、インタラクティブなウェブアプリケーションに分散トレーシングを提供する方法を説明します。
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 11+ がインストールされ、
JAVA_HOMEが適切に設定されていること -
Apache Maven 3.8.6
-
Docker と Docker Compose、または Podman 、および Docker Compose
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、すぐに完成した例に飛んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git 、 アーカイブ をダウンロードします。
このソリューションは、 opentelemetry-quickstart ディレクトリにあります。
Mavenプロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。
このコマンドはMavenプロジェクトを生成し、 quarkus-opentelemetry エクステンションをインポートします。このエクステンションには、デフォルトのOpenTelemetryサポートと、 OTLPのgRPC spanエクスポーターが含まれています。
Quarkusプロジェクトがすでに設定されている場合、プロジェクトのベースディレクトリで次のコマンドを実行することで、 quarkus-opentelemetry エクステンションをプロジェクトに追加できます:
quarkus extension add 'opentelemetry'
./mvnw quarkus:add-extension -Dextensions='opentelemetry'
./gradlew addExtension --extensions='opentelemetry'
これにより、 pom.xml に以下が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
implementation("io.quarkus:quarkus-opentelemetry")
JAX-RSのリソース調査
src/main/java/org/acme/opentelemetry/TracedResource.java のファイルを開くと、以下の内容が表示されます。
package org.acme.opentelemetry;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jboss.logging.Logger;
@Path("/hello")
public class TracedResource {
private static final Logger LOG = Logger.getLogger(TracedResource.class);
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
LOG.info("hello");
return "hello";
}
}
このアプリケーションには、トレースのためのコードが含まれていないことに注意してください。デフォルトでは、このエンドポイントに送信されたリクエストは、コードの変更を必要とせずにトレースされます。
コンフィグレーションの作成
アプリケーション内でOTLP gRPC エクスポーターを設定するには2つの方法があります。
最初のアプローチは、 src/main/resources/application.properties ファイル内でプロパティーを提供することです。
quarkus.application.name=myservice (1)
quarkus.opentelemetry.enabled=true (2)
quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317 (3)
quarkus.opentelemetry.tracer.exporter.otlp.headers=Authorization=Bearer my_secret (4)
quarkus.log.console.format=%d{HH:mm:ss} %-5p traceId=%X{traceId}, parentId=%X{parentId}, spanId=%X{spanId}, sampled=%X{sampled} [%c{2.}] (%t) %s%e%n (5)
# Alternative to the console log
quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}" (6)
| 1 | このアプリケーションから作成されたすべてのスパンには、そのスパンが myservice アプリケーションによって作成されたことを示す OpenTelemetry Resource が含まれます。設定されていない場合は、デフォルトでアーティファクトIDが設定されます。 |
| 2 | OpenTelemetryを有効にするかどうか。デフォルトは true ですが、ここでは無効にできることを示しています。 |
| 3 | スパンを送信するためのgRPCエンドポイント |
| 4 | 認証によく使われるオプションのgRPCヘッダー |
| 5 | ログメッセージにトレース情報を追加します。 |
| 6 | また、アクセスログにのみトレース情報を記載することもできます。この場合、コンソールログ形式の情報を省略する必要があります。 |
アプリケーションの実行
最初のステップは、テレメトリデータを受信して処理し、キャプチャしたトレースを表示する Jaegerにエクスポートするための OpenTelemetry Collectorの設定と起動です。
|
Jaegerはバージョン1.35以降、OTelプロトコルをサポートしています。この場合、コレクターをインストールする必要はなく、トレースデータを直接Jaegerに送ることができます(OTLPレシーバーを有効にした後、この ブログエントリ を参照してください)。 |
otel-collector-config.yaml ファイルを作成して OpenTelemetry Collector を設定します。
receivers:
otlp:
protocols:
grpc:
endpoint: otel-collector:4317
exporters:
jaeger:
endpoint: jaeger-all-in-one:14250
tls:
insecure: true
processors:
batch:
extensions:
health_check:
service:
extensions: [health_check]
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger]
docker-compose up -d OpenTelemetry CollectorとJaegerシステムを、以下の docker-compose.yml ファイルを介して起動します。
version: "2"
services:
# Jaeger
jaeger-all-in-one:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
- "14268:14268"
- "14250:14250"
# Collector
otel-collector:
image: otel/opentelemetry-collector:latest
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml:Z
ports:
- "13133:13133" # Health_check extension
- "4317:4317" # OTLP gRPC receiver
depends_on:
- jaeger-all-in-one
これでアプリケーションを実行する準備が整いました。トレーサーの設定に application.properties を使用している場合:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
または、JVM引数でOTLP gRPCエンドポイントを設定する場合:
quarkus dev -Djvm.args="-Dquarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317"
./mvnw quarkus:dev -Djvm.args="-Dquarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317"
./gradlew --console=plain quarkusDev -Djvm.args="-Dquarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317"
OpenTelemetry Collector、Jaegerシステム、アプリケーションが動作している状態で、提供されているエンドポイントにリクエストを出すことができます。
$ curl http://localhost:8080/hello
hello
最初のリクエストが送信された時点で、ログにトレース情報が表示されるようになります:
10:49:02 INFO traceId=, parentId=, spanId=, sampled= [io.quarkus] (main) Installed features: [cdi, opentelemetry, rest-client, resteasy, smallrye-context-propagation, vertx]
10:49:03 INFO traceId=17ceb8429b9f25b0b879fa1503259456, parentId=3125c8bee75b7ad6, spanId=58ce77c86dd23457, sampled=true [or.ac.op.TracedResource] (executor-thread-1) hello
10:49:03 INFO traceId=ad23acd6d9a4ed3d1de07866a52fa2df, parentId=, spanId=df13f5b45cf4d1e2, sampled=true [or.ac.op.TracedResource] (executor-thread-0) hello
その後、 Jaeger UI にアクセスしてトレース情報を確認します。
CTRL+C を叩いてアプリケーションを停止させます。
JDBC
JDBCインスツルメンテーションは、アプリケーションによって実行される各JDBCクエリのためにスパンを追加します。これを有効にするには、次の依存関係をビルドファイルに追加します。
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-jdbc</artifactId>
</dependency>
implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc")
専用のJDBCドライバを使用するため、データソースとHibernate ORMがそれを使用するように設定する必要があります。
quarkus.datasource.db-kind=postgresql
# add ':otel' to your database URL
quarkus.datasource.jdbc.url=jdbc:otel:postgresql://localhost:5432/mydatabase
# use the 'OpenTelemetryDriver' instead of the one for your database
quarkus.datasource.jdbc.driver=io.opentelemetry.instrumentation.jdbc.OpenTelemetryDriver
追加設定
一部のユースケースでは、OpenTelemetryのカスタム設定が必要になります。 これらのセクションでは、適切に構成するために必要なものについて概説します。
IDジェネレーター
OpenTelemetry エクステンションでは、トレースおよびスパンの識別子を作成する際に、デフォルトでランダムな ID ジェネレーターを使用します。
ベンダー固有のプロトコルの中には、カスタム ID ジェネレーターを必要とするものがありますが、プロデューサーを作成することで、デフォルトの ID ジェネレーターを上書きすることができます。OpenTelemetryエクステンションは、 IdGenerator CDI Beanを検出し、トレーサープロデューサーを構成する際にそれを使用します。
@Singleton
public class CustomConfiguration {
/** Creates a custom IdGenerator for OpenTelemetry */
@Produces
@Singleton
public IdGenerator idGenerator() {
return AwsXrayIdGenerator.getInstance();
}
}
プロパゲーター
OpenTelemetry は、 プロパゲーター を介して分野横断的な関心事を伝播し、状態を保存するための基になる"コンテキスト"を共有します 分散トランザクションの存続期間全体にわたってデータにアクセスします。
デフォルトでは、OpenTelemetryエクステンションは、 W3C Trace Contextと W3C Baggageプロパゲータを有効にしていますが、 設定リファレンスで説明されている propagators 設定を設定することで、サポートされているOpenTelemetryプロパゲータのいずれかを選択することができます。
|
pom.xml
build.gradle
pom.xml
build.gradle
|
リソース
リソースは、テレメトリを生成しているエンティティの表現であり、誰がトレースを生成しているかを特徴づけるために、エクスポートされたトレースに属性を追加します。
設定リファレンス に記述されている resource-attributes トレーサーの設定を行うことで属性を追加することができます。 このプロパティは実行時にオーバーライドできるので、OpenTelemetry 拡張は Quarkus 設定リファレンス に記述されている優先順位に従ってその値を取得します。
カスタムリソースや OpenTelemetry SDK Extensionsで提供されているリソースを使用する必要がある場合は、複数のリソースプロデューサーを作成することができます。OpenTelemetryエクステンションは、 Resource CDI Beanを検出し、トレーサー・プロデューサーを構成する際にそれらをマージします。
@ApplicationScoped
public class CustomConfiguration {
@Produces
@ApplicationScoped
public Resource osResource() {
return OsResource.get();
}
@Produces
@ApplicationScoped
public Resource ecsResource() {
return EcsResource.get();
}
}
サンプラー
サンプラーは、トレースをサンプリングしてエクスポートするかどうかを決定し、収集してコレクターに送信するトレースのサンプル数を減らすことで、ノイズやオーバーヘッドを制御します。
内蔵サンプラーの設定は、 [configuration-reference]に記載されている希望のサンプラー設定を設定するだけで可能です。
カスタムサンプラーを使用する必要がある場合や、 OpenTelemetry SDK Extensionsの1つが提供するサンプラーを使用する必要がある場合は、サンプラー・プロデューサーを作成することができます。OpenTelemetryエクステンションは、 Sampler CDI Beanを検出し、トレーサープロデューサーを構成する際にそれを使用します。
@Singleton
public class CustomConfiguration {
/** Creates a custom sampler for OpenTelemetry */
@Produces
@Singleton
public Sampler sampler() {
return JaegerRemoteSampler.builder()
.setServiceName("my-service")
.build();
}
}
追加の計器
Quarkusエクステンションの中には、トレースが後続の実行に伝搬されることを保証するために追加のコードを必要とするものがあります。これらのセクションでは、プロセスの境界を越えてトレースを伝搬するために必要なことを説明します。
このセクションで説明されている計器は、Quarkusでテストされており、標準モードとネイティブモードの両方で動作します。
CDI
CDI を意識した Bean のメソッドに io.opentelemetry.extension.annotations.WithSpan というアノテーションを付けると、新しい Span が作成され、現在の Trace コンテキストと必要な関係が確立されます。
メソッドパラメータには、 io.opentelemetry.extension.annotations.SpanAttribute アノテーションを付けて、どのメソッドパラメータが Trace の一部となるべきかを示すことができます。
例:
@ApplicationScoped
class SpanBean {
@WithSpan
void span() {
}
@WithSpan("name")
void spanName() {
}
@WithSpan(kind = SERVER)
void spanKind() {
}
@WithSpan
void spanArgs(@SpanAttribute(value = "arg") String arg) {
}
}
使用可能なOpenTelemetry CDI依存関係注入
MicroProfile Telemetry Tracingの仕様に基づき、Quarkusは以下のクラスのCDI依存関係注入をサポートしています。
-
io.opentelemetry.api.OpenTelemetry -
io.opentelemetry.api.trace.Tracer -
io.opentelemetry.api.trace.Span -
io.opentelemetry.api.baggage.Baggage
これらのクラスは、CDIが有効なBeanに注入することができます。例えば、 Tracer は、カスタムスパンを開始するために特に有用です。
@Inject
Tracer tracer;
...
public void tracedWork() {
Span span = tracer.spanBuilder("My custom span")
.setAttribute("attr", "attr.value")
.setParent(Context.current().with(Span.current()))
.setSpanKind(SpanKind.INTERNAL)
.startSpan();
// traced work
span.end();
}
SmallRye Reactive Messaging - Kafka
SmallRye Reactive Messaging extension for Kafkaを使用すると、スパンをKafka Recordに伝搬させることができます。
TracingMetadata tm = TracingMetadata.withPrevious(Context.current());
Message out = Message.of(...).withMetadata(tm);
上記は、生成されている Message に追加できる TracingMetadata オブジェクトを作成し、OpenTelemetry Context を取得して、伝播のために現在のスパンを抽出しています。
エクスポーター
Quarkus OpenTelemetryのデフォルトは、OpenTelemetryで定義されている標準的なOTLPエクスポーターです。
追加のエクスポーターは、Quarkiverseの quarkus-opentelemetry-exporter プロジェクトで利用できるようになる予定です。
OpenTelemetry 設定リファレンス
ビルド時に固定される設定プロパティ - 他のすべての設定プロパティは実行時にオーバーライド可能
タイプ |
デフォルト |
|
|---|---|---|
OpenTelemetry support. OpenTelemetry support is enabled by default. Environment variable: Show more |
boolean |
|
Comma separated list of OpenTelemetry propagators which must be supported.
Valid values are Environment variable: Show more |
文字列のリスト |
|
Support for tracing with OpenTelemetry. Support for tracing will be enabled if OpenTelemetry support is enabled and either this value is true, or this value is unset. Environment variable: Show more |
boolean |
|
A comma separated list of name=value resource attributes that represents the entity producing telemetry (eg. Environment variable: Show more |
文字列のリスト |
|
The sampler to use for tracing.
Valid values are Environment variable: Show more |
string |
|
Environment variable: |
double |
|
If the sampler to use for tracing is parent based.
Valid values are Environment variable: Show more |
boolean |
|
Suppress non-application uris from trace collection. This will suppress tracing of Environment variable: Show more |
boolean |
|
Include static resources from trace collection. Include static resources is disabled by default. Environment variable: Show more |
boolean |
|
OTLP SpanExporter support. OTLP SpanExporter support is enabled by default. Environment variable: Show more |
boolean |
|
The OTLP endpoint to connect to. The endpoint must start with either http:// or https://. Environment variable: Show more |
string |
|
Key-value pairs to be used as headers associated with gRPC requests. The format is similar to the Environment variable: Show more |
文字列のリスト |
|
The maximum amount of time to wait for the collector to process exported spans before an exception is thrown. A value of Environment variable: Show more |
|
|
Compression method to be used by exporter to compress the payload. See Configuration Options for the supported compression methods. Environment variable: Show more |
string |
|
期間フォーマットについて
期間のフォーマットは標準の 数値で始まる期間の値を指定することもできます。この場合、値が数値のみで構成されている場合、コンバーターは値を秒として扱います。そうでない場合は、 |