Ponz Dev Log

ゆるくてマイペースな開発日記

Javaアプリのトレース情報をJaegerにOpenTelemetry Protocolで送りつける

Jaeger v1.35からOpenTelemetry Protocol (OTEL) によるトレース情報を受け付けられるようになりました。 JavaアプリからOTELでトレース情報を送信・参照してみます。

元記事はこちら。

medium.com

検証環境

コンポーネント バージョン
OS macOS Monterey (12.4)
Java OpenJDK Temurin-11.0.15+10
Docker Desktop 4.9.0 (80466)

サンプルアプリ

Jakarta EE (Java EE) で実装された以下2本のアプリを題材とします。

名前 トレース上の名称 説明
フロントエンド・サービス liberty-front-ui ブラウザ上でリクエストを受け付け、バックエンド・サービスにAPIコールを送信する
バックエンド・サービス liberty-backend-service HTTPでリクエストを受け付け、組み込みDB (Derby DB)を操作する

どちらもOpen Libertyアプリケーションサーバ上で稼働するものとします。 アプリ本体はOpen Libertyの以下のサンプルリポジトリを使用します。

github.com

Jaegerを立ち上げる

Midiumの記事に沿ってAll in OneのDockerコンテナを立てます。

docker run --name jaeger \
  -e COLLECTOR_OTLP_ENABLED=true \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  jaegertracing/all-in-one:1.35

コンテナは数秒で起動します。ログを参照して公開した3つのポートのサーバが立ち上がっていればOKです。

docker logs jaeger
{"level":"info", ... ,"msg":"Starting GRPC server on endpoint 0.0.0.0:4317"}
{"level":"info", ... ,"msg":"Starting HTTP server on endpoint 0.0.0.0:4318"}
{"level":"info", ... ,"msg":"Starting HTTP server","port":16686,"addr":":16686"}

アプリケーションに設定を入れる

サンプルアプリはJava製なので、「OpenTelemetry Instrumentation for Java」を使用してトレース情報を取得・送信することにします。 Javaアプリ起動時にこのJava Agentを指定することで、様々なフレームワークやライブラリのトレース情報を自動取得してOTELで送信可能です。

github.com

まずはJava Agentを任意の場所にダウンロードします。 上記のGitHubリポジトリのReleaseページから最新のタグからダウンロードします。 本記事の執筆時点では、Version 1.14.0でした。

cd /path/to/opentelemetry
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

Java Agentでトレース情報を送信するためには、 JVM起動オプションに以下のパラメータをセットする必要があります。

パラメータ名 設定値 説明
otel.exporter.otlp.endpoint http://localhost:4317 トレース情報送信先のOTELサーバ = Jaegerサーバのエンドポイント
otel.traces.exporter otel トレース情報のexporter
otel.metrics.exporter none メトリクス情報のexporter
otel.resource.attributes service.name=<アプリ名> OpenTelemetryリソースの属性

otel.metrics.exporternoneで無効化してください。 本記事で使用するJaegerのバージョンではメトリクスをOTELで直接Jaegerに送信することはまだできません。 設定せずにアプリを起動すると以下のメッセージと共にエラーログが出力されます。

[err] [OkHttp http://localhost:4317/...] ERROR io.opentelemetry.exporter.internal.grpc.OkHttpGrpcExporter - Failed to export metrics. Server responded with UNIMPLEMENTED.

その他に設定できるパラメータは以下を参照してください。

opentelemetry-java/README.md at main · open-telemetry/opentelemetry-java · GitHub

さらにOpen Libertyサーバ固有の設定を1つ実施します。 JVM起動オプションを1箇所で管理するために以下の手順で jvm.options ファイルを作成して上記のパラメータを記載します。

フロントエンド・サービスの例

# サンプルアプリのリポジトリをダウンロード
git clone https://github.com/openliberty/guide-jpa-intro.git
cd guide-jpa-intro/finish/frontendUI

# jvm.optionsファイルを格納するディレクトリを事前に作成
mkdir -p src/main/liberty/config/configDropins/overrides

# jvm.optionsファイルを作成
cat <<EOF > src/main/liberty/config/configDropins/overrides/jvm.options
-javaagent:/path/to/opentelemetry/opentelemetry-javaagent.jar
-Dotel.exporter.otlp.endpoint=http://localhost:4317
-Dotel.traces.exporter=otlp
-Dotel.metrics.exporter=none
-Dotel.resource.attributes=service.name=liberty-frontend-ui
EOF

tree src/main/liberty 
src/main/liberty
└── config
    ├── configDropins
    │   └── overrides
    │       └── jvm.options
    └── server.xml

バックエンド・サービスの例

# サンプルアプリのリポジトリをダウンロード
git clone https://github.com/openliberty/guide-jpa-intro.git
cd guide-jpa-intro/finish/backendServices

# jvm.optionsファイルを格納するディレクトリを事前に作成
mkdir -p src/main/liberty/config/configDropins/overrides

# jvm.optionsファイルを作成
cat <<EOF > src/main/liberty/config/configDropins/overrides/jvm.options
-javaagent:/path/to/opentelemetry/opentelemetry-javaagent.jar
-Dotel.exporter.otlp.endpoint=http://localhost:4317
-Dotel.traces.exporter=otlp
-Dotel.metrics.exporter=none
-Dotel.resource.attributes=service.name=liberty-backend-service
EOF

アプリケーションを起動してトレース情報を送信する

設定が完了したら早速アプリケーションを起動してトレース情報をJaegerに送信します。

# フロントエンド・サービス
cd guide-jpa-intro/finish/frontendUI
mvn liberty:run

# バックエンド・サービス
cd guide-jpa-intro/finish/backendServices
mvn liberty:run

起動時のINFOログにOpenTelemetryのJava Agentのバージョンが表示されていれば準備完了です。

[main] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 1.14.0

ブラウザで http://localhost:9090/eventmanager.jsf を開いて適当に参照、作成、更新、削除と操作します。

ブラウザでサンプルアプリを操作する

Jaegerでトレース情報を参照する

Jaeger UI (http://localhost:16686/) でトレース情報を参照すると、Serviceのプルダウンに先ほどJava Agentと一緒に起動したアプリ名が表示されています。

Serviceにアプリ名が表示されている

フロントエンド・サービスを選択して「Find Traces」ボタンを押すとトレース一覧、それぞれのトレースの実行時刻と処理時間が表示されます。トレース情報が取り込まれていますね。

Jaegerに取り込まれたトレース情報一覧

トレース情報を1つ選択すると自動取得されたトレースのスパンの詳細を確認できます。 フロントエンド・サービスとバックエンド・サービスが1つに繋がって表示されています。

トレース情報の詳細

フロントエンド・サービスからバックエンド・サービスへのPOSTリクエストのスパンを開くと、Tagsに使用しているライブラリ名やリクエスト先のURLが見れました。Apache HTTP ClientでHTTPリクエストを投げているようですね。

トレース スパンの詳細


今回のアップデートでトレース情報を取得・送信する敷居がグッと下がった気がしますね。どこかで使おう。

以上。