Using OpenTelemetry Tracing
このガイドでは、Quarkusアプリケーションで OpenTelemetry (OTel)を利用して、インタラクティブなWebアプリケーションに分散トレースを提供する方法について説明します。
|
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.9
-
Docker と Docker Compose、または Podman 、および Docker Compose
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、すぐに完成した例に飛んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git
、 アーカイブ をダウンロードします。
ソリューションは opentelemetry-quickstart
ディレクトリ にあります。
Mavenプロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=opentelemetry-quickstart"
このコマンドはMavenプロジェクトを生成し、quarkus-opentelemetry
エクステンションをインポートします。このエクステンションには、デフォルトのOpenTelemetryサポートと、https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md[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")
Jakarta REST リソースの調査
src/main/java/org/acme/opentelemetry/TracedResource.java
のファイルを開くと、以下の内容が表示されます。
package org.acme.opentelemetry;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.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";
}
}
このアプリケーションには、トレースのためのコードが含まれていないことに注意してください。デフォルトでは、このエンドポイントに送信されたリクエストは、コードの変更を必要とせずにトレースされます。
コンフィグレーションの作成
By default, the exporters will send out data in batches, using the gRPC protocol and endpoint http://localhost:4317
.
デフォルトのプロパティ値を変更する必要がある場合、 src/main/resources/application.properties
ファイルを使用して、アプリケーション内でデフォルトの OTLP gRPC Exporter を設定する方法の例を以下に示します:
quarkus.application.name=myservice (1)
quarkus.otel.exporter.otlp.endpoint=http://localhost:4317 (2)
quarkus.otel.exporter.otlp.headers=authorization=Bearer my_secret (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)
# Alternative to the console log
quarkus.http.access-log.pattern="...traceId=%{X,traceId} spanId=%{X,spanId}" (5)
1 | All telemetry created from the application will include an OpenTelemetry Resource attribute indicating the telemetry was created by the myservice application. If not set, it will default to the artifact id. |
2 | gRPC endpoint to send the telemetry. If not set, it will default to http://localhost:4317 . |
3 | 認証によく使われるオプションのgRPCヘッダー |
4 | ログメッセージにトレース情報を追加する。 |
5 | また、アクセスログにのみトレース情報を記載することもできます。この場合、コンソールログ形式の情報を省略する必要があります。 |
We provide signal agnostic configurations for the connection related properties, meaning that you can use the same properties for both tracing and metrics when you set:
quarkus.otel.exporter.otlp.endpoint=http://localhost:4317
If you need different configurations for each signal, you can use the specific properties:
quarkus.otel.exporter.otlp.traces.endpoint=http://trace-uri:4317 (1)
quarkus.otel.exporter.otlp.metrics.endpoint=http://metrics-uri:4317 (2)
quarkus.otel.exporter.otlp.logs.endpoint=http://logs-uri:4317 (3)
1 | The endpoint for the traces exporter. |
2 | The endpoint for the metrics exporter. |
3 | The endpoint for the logs exporter. |
If you need that your spans and logs to be exported directly as they finish
(e.g. in a serverless environment / application), you can set this property to true
.
This replaces the default batching of data.
quarkus.otel.simple=true
アプリケーションの実行
First we need to start a system to visualise the OpenTelemetry data. We have 2 options:
-
Start an all-in-one Grafana OTel LGTM system for traces and metrics.
-
Jaeger system just for traces.
Grafana OTel LGTM option
-
Take a look at: Getting Started with Grafana-OTel-LGTM.
This features a Quarkus Dev service including a Grafana for visualizing data, Loki to store logs, Tempo to store traces and Prometheus to store metrics. Also provides an OTel collector to receive the data.
Jaeger to see traces option
Configure and start the OpenTelemetry Collector to receive, process and export telemetry data to Jaeger that will display the captured traces.
Jaeger-all-in-oneは、Jaegerエージェント、OTelコレクター、クエリサービス/UIを含みます。分離型コレクタをインストールする必要はありません。トレースデータを直接Jaegerに送ることができます(OTLPレシーバーを有効にした後、詳細はこちらの ブログエントリ などをご覧ください)。 |
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" # Jaeger UI
- "14268:14268" # Receive legacy OpenTracing traces, optional
- "4317:4317" # OTLP gRPC receiver
- "4318:4318" # OTLP HTTP receiver
- "14250:14250" # Receive from external otel-collector, optional
environment:
- COLLECTOR_OTLP_ENABLED=true
オプションのポートは必要ないものは外しておいた方が良いです。
Start the application
これでアプリケーションを実行する準備が整いました。トレーサーの設定に application.properties
を使用している場合:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
または、JVM引数でOTLP gRPCエンドポイントを設定する場合:
quarkus dev -Djvm.args="-Dquarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317"
./mvnw quarkus:dev -Djvm.args="-Dquarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317"
./gradlew --console=plain quarkusDev -Djvm.args="-Dquarkus.otel.exporter.otlp.traces.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, resteasy-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
を押すか、 q
と入力して、アプリケーションを停止してください。
JDBC
JDBCインスツルメンテーションは、アプリケーションによって実行される各JDBCクエリのためにスパンを追加します。これを有効にするには、次の依存関係をビルドファイルに追加します。
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-jdbc</artifactId>
</dependency>
implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc")
専用のJDBCデータソースラッパーを使用するため、データソースのテレメトリーを有効にする必要があります:
# enable tracing
quarkus.datasource.jdbc.telemetry=true
# configure datasource
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydatabase
追加設定
一部のユースケースでは、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プロパゲータのいずれかを選択することができます。
追加プロパゲーター
-
b3
,b3multi
,jaeger
,ottrace
のプロパゲータは、プロジェクトに trace-propagatorsエクステンションを依存関係として追加する必要があります。
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
</dependency>
implementation("io.opentelemetry:opentelemetry-extension-trace-propagators")
-
xray
プロパゲーターは、お客様のプロジェクトに aws エクステンションを依存関係として追加することを必要とします。
<dependency>
<groupId>io.opentelemetry.contrib</groupId>
<artifactId>opentelemetry-aws-xray-propagator</artifactId>
</dependency>
implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
Customise Propagator
To customise the propagation header you can implement the TextMapPropagatorCustomizer
interface. This can be used, as an example, to restrict propagation of OpenTelemetry trace headers and prevent potentially sensitive data to be sent to third party systems.
/**
* /**
* Meant to be implemented by a CDI bean that provides arbitrary customization for the TextMapPropagator
* that are to be registered with OpenTelemetry
*/
public interface TextMapPropagatorCustomizer {
TextMapPropagator customize(Context context);
interface Context {
TextMapPropagator propagator();
ConfigProperties otelConfigProperties();
}
}
リソース
See the main OpenTelemetry Guide resources section.
End User attributes
When enabled, Quarkus adds OpenTelemetry End User attributes as Span attributes. Before you enable this feature, verify that Quarkus Security extension is present and configured. More information about the Quarkus Security can be found in the Quarkus Security overview.
The attributes are only added when authentication has already happened on a best-efforts basis.
Whether the End User attributes are added as Span attributes depends on authentication and authorization configuration of your Quarkus application.
If you create custom Spans prior to the authentication, Quarkus cannot add the End User attributes to them.
Quarkus is only able to add the attributes to the Span that is current after the authentication has been finished.
Another important consideration regarding custom Spans is active CDI request context that is used to propagate Quarkus SecurityIdentity
.
In principle, Quarkus is able to add the End User attributes when the CDI request context has been activated for you before the custom Spans are created.
quarkus.otel.traces.eusp.enabled=true (1)
quarkus.http.auth.proactive=true (2)
1 | Enable the End User Attributes feature so that the SecurityIdentity principal and roles are added as Span attributes.
The End User attributes are personally identifiable information, therefore make sure you want to export them before you enable this feature. |
2 | Optionally enable proactive authentication. The best possible results are achieved when proactive authentication is enabled because the authentication happens sooner. A good way to determine whether proactive authentication should be enabled in your Quarkus application is to read the Quarkus Proactive authentication guide. |
This feature is not supported when a custom Jakarta REST SecurityContexts is used. |
サンプラー
A sampler decides whether a trace should be discarded or forwarded, effectively managing noise and reducing overhead by limiting the number of collected traces sent to the collector.
Quarkus comes equipped with a built-in sampler, and you also have the option to create your custom sampler.
To use the built-in sampler, you can configure it by setting the desired sampler parameters as detailed in the OpenTelemetry 設定リファレンス. As an example, you can configure the sampler to retain 50% of the traces:
# build time property only:
quarkus.otel.traces.sampler=traceidratio
# Runtime property:
quarkus.otel.traces.sampler.arg=0.5
An interesting use case for the sampler is to activate and deactivate tracing export at runtime, according to this example:
|
カスタムサンプラーを使用する必要がある場合、現在2種類の方法があります:
サンプラー CDI プロデューサー
You can create a sampler CDI producer. The Quarkus OpenTelemetry extension will detect the Sampler
CDI bean and will use it when configuring the Tracer.
@Singleton
public class CustomConfiguration {
/** Creates a custom sampler for OpenTelemetry */
@Produces
@Singleton
public Sampler sampler() {
return JaegerRemoteSampler.builder()
.setServiceName("my-service")
.build();
}
}
OTelサンプラーSPI
This will use the SPI hooks available with the OTel Autoconfiguration. You can create a simple Sampler class:
public class CustomSPISampler implements Sampler {
@Override
public SamplingResult shouldSample(Context context,
String s,
String s1,
SpanKind spanKind,
Attributes attributes,
List<LinkData> list) {
// Do some sampling here
return Sampler.alwaysOn().shouldSample(context, s, s1, spanKind, attributes, list);
}
@Override
public String getDescription() {
return "custom-spi-sampler-description";
}
}
Then a Sampler Provider:
public class CustomSPISamplerProvider implements ConfigurableSamplerProvider {
@Override
public Sampler createSampler(ConfigProperties configProperties) {
return new CustomSPISampler();
}
@Override
public String getName() {
return "custom-spi-sampler";
}
}
Write the SPI loader text file at resources/META-INF/services
with name io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider
containing the full qualified name of the CustomSPISamplerProvider
class.
Then activate on the configuration:
quarkus.otel.traces.sampler=custom-spi-sampler
As you can see, CDI is much simpler to work with.
追加の計器
Quarkusエクステンションの中には、トレースが後続の実行に伝搬されることを保証するために追加のコードを必要とするものがあります。これらのセクションでは、プロセスの境界を越えてトレースを伝搬するために必要なことを説明します。
このセクションで説明されている計器は、Quarkusでテストされており、標準モードとネイティブモードの両方で動作します。
CDI
Annotating a method in any CDI aware bean with the io.opentelemetry.instrumentation.annotations.WithSpan
annotation will create a new Span and establish any required relationships with the current Trace context.
Annotating a method in any CDI aware bean with the io.opentelemetry.instrumentation.annotations.AddingSpanAttributes
will not create a new span but will add annotated method parameters to attributes in the current span.
If a method is annotated by mistake with @AddingSpanAttributes
and @WithSpan
annotations, the @WithSpan
annotation will take precedence.
Method parameters can be annotated with the io.opentelemetry.instrumentation.annotations.SpanAttribute
annotation to
indicate which method parameters should be part of the span. The parameter name can be customized as well.
例:
@ApplicationScoped
class SpanBean {
@WithSpan
void span() {
}
@WithSpan("name")
void spanName() {
}
@WithSpan(kind = SERVER)
void spanKind() {
}
@WithSpan
void spanArgs(@SpanAttribute(value = "arg") String arg) {
}
@AddingSpanAttributes
void addArgumentToExistingSpan(@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();
}
Quarkus Messaging - Kafka
When using the Quarkus Messaging extension for Kafka, we are able to propagate the span into the Kafka Record with:
TracingMetadata tm = TracingMetadata.withPrevious(Context.current());
Message out = Message.of(...).withMetadata(tm);
上記は、生成されている Message
に追加できる TracingMetadata
オブジェクトを作成し、OpenTelemetry Context
を取得して、伝播のために現在のスパンを抽出しています。
Quarkus Security Events
Quarkus supports exporting of the Security events as OpenTelemetry Span events.
quarkus.otel.security-events.enabled=true (1)
1 | Export Quarkus Security events as OpenTelemetry Span events. |
エクスポーター
See the main OpenTelemetry Guide exporters section.
Quarkus core extensions instrumented with OpenTelemetry tracing
Disable parts of the automatic tracing
Automatic tracing instrumentation parts can be disabled by setting quarkus.otel.instrument.*
properties to false
.
例:
quarkus.otel.instrument.grpc=false
quarkus.otel.instrument.messaging=false
quarkus.otel.instrument.resteasy-client=false
quarkus.otel.instrument.rest=false
quarkus.otel.instrument.resteasy=false
OpenTelemetry 設定リファレンス
See the main OpenTelemetry Guide configuration reference.