The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

OpenTracingの使用

このガイドでは、QuarkusアプリケーションがOpenTracingを利用してインタラクティブなウェブアプリケーションのための分散トレースを提供する方法について説明します。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 11+ がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.8.1+

  • 動作するコンテナランタイム(Docker, Podman)

  • 使用したい場合、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

アーキテクチャ

このガイドでは、分散トレースを実証するための簡単なRESTアプリケーションを作成します。

ソリューション

次のセクションで紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、すぐに完成した例に飛んでも構いません。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

ソリューションは opentracing-quickstart ディレクトリ にあります。

Mavenプロジェクトの作成

まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します:

CLI
quarkus create app org.acme:opentracing-quickstart \
    --extension=resteasy-reactive,quarkus-smallrye-opentracing \
    --no-code
cd opentracing-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストール方法については、Quarkus CLIガイドをご参照ください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.11.2.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=opentracing-quickstart \
    -Dextensions="resteasy-reactive,quarkus-smallrye-opentracing" \
    -DnoCode
cd opentracing-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

このコマンドはMaven プロジェクトを生成し、OpenTracingのサポートとデフォルトの Jaeger トレーサーを含む smallrye-opentracing エクステンションをインポートします。

すでにQuarkusプロジェクトを設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに smallrye-opentracing エクステンションを追加することができます:

CLI
quarkus extension add 'smallrye-opentracing'
Maven
./mvnw quarkus:add-extension -Dextensions="smallrye-opentracing"
Gradle
./gradlew addExtension --extensions="smallrye-opentracing"

これにより、ビルドファイルに以下の内容が追加されます:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-opentracing</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-smallrye-opentracing")

JAX-RSリソースの調査

以下の内容で src/main/java/org/acme/opentracing/TracedResource.java ファイルを作成します:

package org.acme.opentracing;

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"); (1)
        return "hello";
    }
}
1 ログイベントは OpenTracing の情報も含んでいます。OpenTracingの情報をコンソール出力するためには、必要なOpenTracingイベントのキーを持つコンソールログハンドラを application.properties ファイルで定義する必要があります。

このアプリケーションにはトレース用のコードが含まれていないことに注意してください。デフォルトでは、このエンドポイントに送信されたリクエストは、コードを変更することなくトレースされます。トレース情報を拡張することも可能です。これは、 MicroProfile OpenTracing の実装である SmallRye OpenTracing で実現できます。

設定の作成

アプリケーション内でJaeger トレーサーを設定するには、2つの方法があります。

最初のアプローチは、 src/main/resources/application.properties ファイル内でプロパティーを設定することです:

quarkus.jaeger.service-name=myservice (1)
quarkus.jaeger.sampler-type=const (2)
quarkus.jaeger.sampler-param=1 (3)
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 (4)
1 quarkus.jaeger.service-name プロパティー (または JAEGER_SERVICE_NAME 環境変数) を指定しなかった場合は、"no-op" トレーサーが設定され、バックエンドにトレースデータは報告されなくなります。
2 定数サンプリングを行うサンプラーを設定します。
3 すべてのリクエストをサンプリングします。すべてのリクエストをサンプリングしたくない場合は、sampler-param をに0から1の間の値を設定します (例: 0.50)。
4 ログメッセージにトレースIDを追加します。

2つ目の方法は、プロパティを 環境変数 として指定する方法です。これらは、次のセクションに示すように jvm.args として指定できます。

アプリケーションの実行

まず、トレースシステムを起動し、キャプチャしたトレースを収集・表示します:

docker run -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 jaegertracing/all-in-one:latest

これでアプリケーションを実行する準備が整いました。もし、トレーサーの設定に application.properties を使っている場合は次のようにします:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

または、環境変数でトレーサーを設定する場合:

CLI
quarkus dev -Djvm.args="-DJAEGER_SERVICE_NAME=myservice -DJAEGER_SAMPLER_TYPE=const -DJAEGER_SAMPLER_PARAM=1"
Maven
./mvnw quarkus:dev -Djvm.args="-DJAEGER_SERVICE_NAME=myservice -DJAEGER_SAMPLER_TYPE=const -DJAEGER_SAMPLER_PARAM=1"
Gradle
./gradlew --console=plain quarkusDev -Djvm.args="-DJAEGER_SERVICE_NAME=myservice -DJAEGER_SAMPLER_TYPE=const -DJAEGER_SAMPLER_PARAM=1"

アプリケーションとトレースシステムの両方が起動したら、提供されたエンドポイントにリクエストを行うことができます:

$ curl http://localhost:8080/hello
hello

最初のリクエストが送信されると、アプリ内のJaegerトレーサーが初期化されます:

2019-10-16 09:35:23,464 INFO  [io.jae.Configuration] (executor-thread-1) Initialized tracer=JaegerTracer(version=Java-0.34.0, serviceName=myservice, reporter=RemoteReporter(sender=UdpSender(), closeEnqueueTimeout=1000), sampler=ConstSampler(decision=true, tags={sampler.type=const, sampler.param=true}), tags={hostname=localhost.localdomain, jaeger.version=Java-0.34.0, ip=127.0.0.1}, zipkinSharedRpcSpan=false, expandExceptionLogs=false, useTraceId128Bit=false)
13:20:11 INFO  traceId=1336b2b0a76a96a3, parentId=0, spanId=1336b2b0a76a96a3, sampled=true [or.ac.qu.TracedResource] (executor-thread-63) hello

その後、 Jaeger UI にアクセスしてトレース情報を確認します。

CTRL+C を押して、アプリケーションを停止します。

追加メソッドのトレース

REST エンドポイントは自動的にトレースされます。追加でメソッドをトレースする必要がある場合は、CDI beanのクラスや非privateのメソッドに org.eclipse.microprofile.opentracing.Traced アノテーションを追加することができます。

これは、非RESTコール(メッセージからのリクエストなど)からの着信リクエストをトレースしたり、トレース内にスパンを作成したりするのに便利です。

ここでは、メソッドがトレースされている FrancophoneService の例を示します。

import javax.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.opentracing.Traced;

@Traced
@ApplicationScoped
public class FrancophoneService {

    public String bonjour() {
        return "bonjour";
    }
}
OpenTracingの機能をリアクティブなメッセージングベースのアプリケーションに追加する最良の方法は、すべての受信メソッドに Traced アノテーションを追加することです。

追加のInstrumentation

OpenTracing API Contributionsプロジェクト では、様々な技術/コンポーネントにトレースを追加するための追加の計器 (Instrumentation) を提供しています。

このセクションで説明されているInstrumentationは、Quarkusでテストされており、標準モードとネイティブモードの両方で動作します。

JDBC

JDBC Instrumentation は 、アプリケーションが実行するJDBCクエリごとにスパンを追加します。これを有効にするには、ビルドファイルに次の依存関係を追加します:

pom.xml
<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-jdbc</artifactId>
</dependency>
build.gradle
implementation("io.opentracing.contrib:opentracing-jdbc")

Then, you need to enable it in the configuration:

quarkus.datasource.jdbc.tracing=true

quarkus.datasource.jdbc.tracing is a build time configuration property: it makes sure all the tracing infrastructure is included in your application.

This is especially important when building a native executable as we need to make sure the OpenTracing JDBC driver has been registered for reflection, together with the underlying JDBC driver.

The Agroal extension will take care of adjusting the JDBC URL with the tracing prefix when tracing is enabled, so you do not have to adjust the JDBC URL yourself.

By default, when quarkus.datasource.jdbc.tracing is true, tracing is enabled at runtime but you can explicitly disable it by setting the following property:

quarkus.datasource.jdbc.tracing.enabled=false

This way, you can have your Quarkus application ready for tracing and toggle JDBC tracing at runtime.

Kafka

Kafka instrumentation は、Kafka トピックとの間で送受信されるメッセージごとにスパンを追加します。これを有効にするには、ビルドファイルに以下の依存関係を追加します:

pom.xml
<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-kafka-client</artifactId>
</dependency>
build.gradle
implementation("io.opentracing.contrib:opentracing-kafka-client")

KafkaのProducerとConsumerに登録する必要があるOpenTracingのインターセプターが含まれています。

Kafkaのガイド に従った場合、以下のように generated-priceprices のチャンネルにインターセプターを追加することができます:

# Configure the Kafka sink (we write to it)
mp.messaging.outgoing.generated-price.connector=smallrye-kafka
mp.messaging.outgoing.generated-price.topic=prices
mp.messaging.outgoing.generated-price.value.serializer=org.apache.kafka.common.serialization.IntegerSerializer
mp.messaging.outgoing.generated-price.interceptor.classes=io.opentracing.contrib.kafka.TracingProducerInterceptor

# Configure the Kafka source (we read from it)
mp.messaging.incoming.prices.connector=smallrye-kafka
mp.messaging.incoming.prices.value.deserializer=org.apache.kafka.common.serialization.IntegerDeserializer
mp.messaging.incoming.prices.interceptor.classes=io.opentracing.contrib.kafka.TracingConsumerInterceptor
interceptor.classes はカンマで区切られたクラスのリストを指定できます。

MongoDBクライアント

Mongo Driver instrumentation は 、アプリケーションが実行するコマンドごとにスパンを追加します。これを有効にするには、ビルドファイルに次の依存関係を追加します:

pom.xml
<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-mongo-common</artifactId>
</dependency>
build.gradle
implementation("io.opentracing.contrib:opentracing-mongo-common")

これには、mongoクライアントの設定に登録されるOpenTracing CommandListenerが含まれています。 MongoDBのガイド に従い、以下のようにconfigプロパティを定義してコマンドリスナーを登録します:

# Enable tracing commands in mongodb client
quarkus.mongodb.tracing.enabled=true

Zipkin互換モード

これを有効にするには、ビルドファイルに以下の依存関係を追加します:

pom.xml
<dependency>
    <groupId>io.jaegertracing</groupId>
    <artifactId>jaeger-zipkin</artifactId>
</dependency>
build.gradle
implementation("io.jaegertracing:jaeger-zipkin")

これはリクエストを zipkin フォーマットに変換するための依存関係を含んでいます。 zipkin 互換モードは、以下のように config プロパティを定義した後に有効になります:

# Enable zipkin compatibility mode
quarkus.jaeger.zipkin.compatibility-mode=true

Jaeger構成リファレンス

ビルド時に固定される設定プロパティ - それ以外の設定プロパティは実行時に上書き可能

Configuration property

タイプ

デフォルト

Defines if the Jaeger extension is enabled.

Environment variable: QUARKUS_JAEGER_ENABLED

boolean

true

Whether metrics are published in case a metrics extension is present.

Environment variable: QUARKUS_JAEGER_METRICS_ENABLED

boolean

false

The traces endpoint, in case the client should connect directly to the Collector, like http://jaeger-collector:14268/api/traces

Environment variable: QUARKUS_JAEGER_ENDPOINT

URI

Authentication Token to send as "Bearer" to the endpoint

Environment variable: QUARKUS_JAEGER_AUTH_TOKEN

string

Username to send as part of "Basic" authentication to the endpoint

Environment variable: QUARKUS_JAEGER_USER

string

Password to send as part of "Basic" authentication to the endpoint

Environment variable: QUARKUS_JAEGER_PASSWORD

string

The hostname and port for communicating with agent via UDP

Environment variable: QUARKUS_JAEGER_AGENT_HOST_PORT

host:port

Whether the reporter should also log the spans

Environment variable: QUARKUS_JAEGER_REPORTER_LOG_SPANS

boolean

The reporter’s maximum queue size

Environment variable: QUARKUS_JAEGER_REPORTER_MAX_QUEUE_SIZE

int

The reporter’s flush interval

Environment variable: QUARKUS_JAEGER_REPORTER_FLUSH_INTERVAL

Duration

The sampler type (const, probabilistic, ratelimiting or remote)

Environment variable: QUARKUS_JAEGER_SAMPLER_TYPE

string

The sampler parameter (number)

Environment variable: QUARKUS_JAEGER_SAMPLER_PARAM

BigDecimal

The host name and port when using the remote controlled sampler

Environment variable: QUARKUS_JAEGER_SAMPLER_MANAGER_HOST_PORT

host:port

The service name

Environment variable: QUARKUS_JAEGER_SERVICE_NAME

string

A comma separated list of name = value tracer level tags, which get added to all reported spans. The value can also refer to an environment variable using the format ${envVarName:default}, where the :default is optional, and identifies a value to be used if the environment variable cannot be found

Environment variable: QUARKUS_JAEGER_TAGS

string

Comma separated list of formats to use for propagating the trace context. Defaults to the standard Jaeger format. Valid values are jaeger and b3

Environment variable: QUARKUS_JAEGER_PROPAGATION

string

The sender factory class name

Environment variable: QUARKUS_JAEGER_SENDER_FACTORY

string

Whether the trace context should be logged.

Environment variable: QUARKUS_JAEGER_LOG_TRACE_CONTEXT

boolean

true

Whether the registration of tracer as the global tracer should be disabled. This setting should only be turned on in tests that need to install a mock tracer.

Environment variable: QUARKUS_JAEGER_DISABLE_TRACER_REGISTRATION

boolean

false

Whether jaeger should run in zipkin compatibility mode

Environment variable: QUARKUS_JAEGER_ZIPKIN_COMPATIBILITY_MODE

boolean

false

期間フォーマットについて

期間のフォーマットは標準の java.time.Duration フォーマットを使用します。詳細は Duration#parse() javadoc を参照してください。

数値で始まる期間の値を指定することもできます。この場合、値が数値のみで構成されている場合、コンバーターは値を秒として扱います。そうでない場合は、 PT が暗黙的に値の前に付加され、標準の java.time.Duration 形式が得られます。