広告サービス
このサービスは、コンテキストキーに基づいてユーザーに表示する適切な広告を決定します。 広告はストアで販売されている商品に対するものです。
自動計装
このサービスは、gRPC などのライブラリを自動的に計装し、OpenTelemetry SDK を設定するために、OpenTelemetry Java エージェントに依存しています。
エージェントは -javaagent コマンドライン引数を使用してプロセスに渡されます。
コマンドライン引数は Dockerfile の JAVA_TOOL_OPTIONS を通じて追加され、自動生成された Gradle 起動スクリプトで利用されます。
ENV JAVA_TOOL_OPTIONS=-javaagent:/app/opentelemetry-javaagent.jar
トレース
自動計装されたスパンへの属性の追加
自動計装されたコードの実行中に、コンテキストから現在のスパンを取得できます。
Span span = Span.current();
スパンへの属性の追加は、スパンオブジェクトの setAttribute を使用して行います。
getAds 関数では、スパンに複数の属性が追加されます。
span.setAttribute("app.ads.contextKeys", req.getContextKeysList().toString());
span.setAttribute("app.ads.contextKeys.count", req.getContextKeysCount());
スパンイベントの追加
スパンへのイベントの追加は、スパンオブジェクトの addEvent を使用して行います。
getAds 関数では、例外がキャッチされたときに属性付きのイベントが追加されます。
span.addEvent("Error", Attributes.of(AttributeKey.stringKey("exception.message"), e.getMessage()));
スパンステータスの設定
操作の結果がエラーの場合、スパンオブジェクトの setStatus を使用して、スパンステータスを適切に設定する必要があります。
getAds 関数では、例外がキャッチされたときにスパンステータスが設定されます。
span.setStatus(StatusCode.ERROR);
新しいスパンの作成
新しいスパンは Tracer.spanBuilder("spanName").startSpan() を使用して作成および開始できます。
新しく作成されたスパンは Span.makeCurrent() を使用してコンテキストに設定する必要があります。
getRandomAds 関数は、新しいスパンを作成し、コンテキストに設定し、操作を実行し、最後にスパンを終了します。
// 新しいスパンを手動で作成して開始する
Tracer tracer = GlobalOpenTelemetry.getTracer("ad");
Span span = tracer.spanBuilder("getRandomAds").startSpan();
// スパンをコンテキストに配置し、子スパンが開始された場合に親が適切に設定されるようにする
try (Scope ignored = span.makeCurrent()) {
Collection<Ad> allAds = adsMap.values();
for (int i = 0; i < MAX_ADS_TO_SERVE; i++) {
ads.add(Iterables.get(allAds, random.nextInt(allAds.size())));
}
span.setAttribute("app.ads.count", ads.size());
} finally {
span.end();
}
メトリクス
メトリクスの初期化
スパンの作成と同様に、メトリクスを作成する最初のステップは Meter インスタンスの初期化です。
たとえば GlobalOpenTelemetry.getMeter("ad") を使用します。
そこから、Meter インスタンスで利用可能なさまざまなビルダーメソッドを使用して、目的のメトリクス計装を作成します。
例:
meter
.counterBuilder("app.ads.ad_requests")
.setDescription("Counts ad requests by request and response type")
.build();
OTel 以外のカスタムメトリクスの橋渡し(Prometheus クライアントライブラリ)
広告サービスは、OpenTelemetry SDK のかわりに Prometheus Java クライアントライブラリを使用して、少数のカスタムメトリクスも公開しています。
これらのメトリクスは別の HTTP エンドポイント(AD_PROMETHEUS_PORT の /metrics、デフォルトは 9465)で公開され、OpenTelemetry Collector の prometheus レシーバーによってスクレイプされ、OTel SDK メトリクスと同じパイプラインに転送されます。
private static final Counter adsServedCounter =
Counter.builder()
.name("demo_ad_served_total")
.help("Total number of ads served, labeled by category")
.labelNames("category")
.register();
HTTPServer prometheusServer =
HTTPServer.builder().port(prometheusPort).buildAndStart();
これは OTel 導入時によくあるパターンを示すために意図的に含まれています。
組織は、ライブラリ、サードパーティのエクスポーター、またはレガシーサービスにすでに大量の Prometheus 計装を持っていることが多く、すべてを一から書き直すことなく、それらのメトリクスを OpenTelemetry ネイティブのパイプラインに取り込みたいと考えています。
Collector の prometheus レシーバーは、これを可能にする橋渡しです。
これを接続する Collector の設定は次のとおりです。
receivers:
prometheus/ad:
config:
scrape_configs:
- job_name: ad
scrape_interval: 10s
static_configs:
- targets: ['ad:${env:AD_PROMETHEUS_PORT}']
推奨事項:これは過渡的なパターンとして扱ってください。 新しいカスタムメトリクスには、OpenTelemetry SDK を直接使用してください。 既存の Prometheus クライアントメトリクスについては、周辺のコードに手を加える際に段階的に移行するか、集中的なリファクタリングで対応してください。
OpenTelemetry と Prometheus のテレメトリーを混在させる際のよくある課題:
- ID の不一致:
service.nameとservice.instance.idが2つのパイプライン間で一致しない可能性があります。 - 二重のメンタルモデル:Prometheus と OTel は異なる概念(ラベルと属性、異なるセマンティック規約)を使用し、API、取り込みパイプライン、そして場合によっては異なるエンリッチメントルールが別々に存在します。
- 一貫性のないコード:古いメトリクスに Prometheus クライアントの呼び出しを使い、新しいメトリクスに OTel API の呼び出しを使うと、コードベースに統一的なスタイルがなくなります。
現在生成されているメトリクス
以下のメトリクス名はすべて、Prometheus/Grafana では . 文字が _ に変換されて表示されることに注意してください。
カスタムメトリクス
現在利用可能なカスタムメトリクスは以下のとおりです。
app.ads.ad_requests(OpenTelemetry SDK):広告リクエストのカウンターで、リクエストがコンテキストキーでターゲット指定されたかどうか、およびレスポンスがターゲット広告かランダム広告かを示すディメンションを持ちます。demo_ad_served_total(Prometheus クライアントライブラリ、Collector によりスクレイプ):配信された広告のカウンターで、category(例:telescopes、binoculars、random)でラベル付けされています。 上記の OTel 以外のカスタムメトリクスの橋渡しを参照してください。
自動計装メトリクス
アプリケーションで利用可能な自動計装メトリクスは以下のとおりです。
ログ
広告サービスは Log4J を使用しており、OTel Java エージェントによって自動的に設定されます。
ログレコードにトレースコンテキストが含まれるため、ログとトレースの相関が可能です。
フィードバック
このページは役に立ちましたか?
Thank you. Your feedback is appreciated!
Please let us know how we can improve this page. Your feedback is appreciated!