ヘルスチェック、readiness プローブ、その他の定期的なリクエストは、トレースにノイズを加え、コストを増加させるスパンを生成します。カスタムの OpenTelemetry サンプラーを使用して、これらのスパンがアプリケーションから送信される前にドロップします。
OpenTelemetry 向けマネージドサービスは、Java および Node.js アプリケーションのスパンフィルタリングをサポートしています。
仕組み
OpenTelemetry は、サンプラーを使用して各スパンをレコードおよびエクスポートするかどうかを決定します。カスタムサンプラーは、スパン名や HTTP ターゲットパスなどのスパンのプロパティを検査し、次の 2 つの決定のいずれかを返します:
DROP (
SamplingDecision.DROP) -- スパンは破棄されます。レコードもエクスポートもされません。RECORD_AND_SAMPLE (
SamplingDecision.RECORD_AND_SAMPLE) -- スパンは保持され、通常どおりレコードおよびエクスポートされます。
不要なスパンに一致し、DROP を返すサンプラーを作成することで、ソースでノイズを除去します。
メソッドの選択
適切なアプローチは、インストルメンテーションのセットアップとプログラミング言語によって異なります。
Java
| メソッド | 使用する状況 | 必要なコード変更 |
|---|---|---|
| エージェント拡張 | OpenTelemetry Java エージェントによる自動インストルメンテーション。アプリケーションコードの変更は不要です | 別の JAR をビルド |
| SDK サンプラー | OpenTelemetry SDK for Java による手動インストルメンテーション | サンプラークラスをアプリケーションコードに追加 |
Node.js
| メソッド | 使用する状況 | 必要なコード変更 |
|---|---|---|
| 作成時にフィルタリング | 特定の HTTP リクエストに対してスパンが作成されないようにする | HttpInstrumentation で ignoreIncomingRequestHook |
| エクスポート時にフィルタリング | スパン作成後に評価される属性に基づいてスパンをドロップ | カスタムサンプラークラスを実装 |
Java
OpenTelemetry Java エージェント用のエージェント拡張の作成
Java エージェント拡張としてカスタムサンプラーをビルドします。このアプローチにより、フィルタリングロジックをアプリケーションコードから分離できます。
前提条件
開始する前に、以下を確認してください:
OpenTelemetry Java エージェントで自動的にインストルメンテーションされたアプリケーション。セットアップ手順については、「Java アプリケーションのトレースデータを OpenTelemetry を使用して送信する」をご参照ください。
拡張 JAR をビルドするための Apache Maven のインストール
ステップ 1: Maven プロジェクトの作成
エージェント拡張をビルドするための新しい Maven プロジェクトを作成します。
ステップ 2: 依存関係の追加
次の依存関係を pom.xml ファイルに追加します。
すべての OpenTelemetry 依存関係は、使用する OpenTelemetry Java エージェントのバージョンと一致する必要があります。次の例では、バージョン 1.28.0 を使用しています。
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>io.opentelemetry.javaagent</groupId>
<artifactId>opentelemetry-javaagent</artifactId>
<version>1.28.0</version>
<!--スコープを compile に設定します。-->
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-trace</artifactId>
<version>1.28.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
<version>1.28.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-semconv</artifactId>
<version>1.28.0-alpha</version>
</dependency>ステップ 3: サンプラーの実装
io.opentelemetry.sdk.trace.samplers.Sampler インターフェイスを実装するクラスを作成します。shouldSample メソッドでフィルタリングルールを定義し、getDescription からサンプラー名を返します。
shouldSample-- 各スパンを評価し、破棄するスパンにはSamplingResult.create(SamplingDecision.DROP)を、保持するスパンにはSamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE)を返します。getDescription-- サンプラー名を返します。
次の例では、spanName1 または spanName2 という名前のスパン、および http.target 属性が /api/checkHealth または /health/checks のスパンをドロップします:
package org.example;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
import io.opentelemetry.sdk.trace.samplers.SamplingResult;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.*;
public class SpanFilterSampler implements Sampler {
// ドロップするスパン名
private static List<String> EXCLUDED_SPAN_NAMES = Collections.unmodifiableList(
Arrays.asList("spanName1", "spanName2")
);
// ドロップする HTTP ターゲットパス
private static List<String> EXCLUDED_HTTP_REQUEST_TARGETS = Collections.unmodifiableList(
Arrays.asList("/api/checkHealth", "/health/checks")
);
@Override
public SamplingResult shouldSample(Context parentContext, String traceId, String name,
SpanKind spanKind, Attributes attributes, List<LinkData> parentLinks) {
String httpTarget = attributes.get(SemanticAttributes.HTTP_TARGET) != null
? attributes.get(SemanticAttributes.HTTP_TARGET) : "";
if (EXCLUDED_SPAN_NAMES.contains(name)
|| EXCLUDED_HTTP_REQUEST_TARGETS.contains(httpTarget)) {
return SamplingResult.create(SamplingDecision.DROP);
}
return SamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE);
}
@Override
public String getDescription() {
return "SpanFilterSampler";
}
}ステップ 4: サンプラープロバイダーの実装
io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider を実装するクラスを作成します。このプロバイダーは、Java エージェントの自動構成メカニズムにサンプラーを登録します。
createSampler-- サンプラーのインスタンスを返します。getName-- サンプラー名を返します。Java エージェントはこの名前を使用してサンプラーを特定します。
package org.example;
import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider;
import io.opentelemetry.sdk.trace.samplers.Sampler;
@AutoService(ConfigurableSamplerProvider.class)
public class SpanFilterSamplerProvider implements ConfigurableSamplerProvider {
@Override
public Sampler createSampler(ConfigProperties configProperties) {
return new SpanFilterSampler();
}
@Override
public String getName() {
return "SpanFilterSampler";
}
}ステップ 5: 拡張 JAR のビルド
プロジェクトを JAR ファイルにパッケージ化します:
mvn clean packageJAR ファイルは target ディレクトリに生成されます。
ステップ 6: 起動時に拡張をロード
アプリケーションの起動時にカスタムサンプラーを指定します。JVM システムプロパティまたは環境変数のいずれかを使用します。
オプション A: JVM システムプロパティ
-Dotel.traces.sampler=<your-sampler-name> を JVM 起動パラメーターに追加します。<your-sampler-name> を getName メソッドから返される値に置き換えます。
オプション B: 環境変数
OTEL_TRACES_SAMPLER 環境変数をサンプラー名に設定します:
次のプレースホルダーを実際の値に置き換えてください:
| プレースホルダー | 説明 |
|---|---|
<your-sampler-name> | getName |
<token> | OTLP エンドポイントの認証トークン |
<endpoint> | OTLP エクスポーターのエンドポイント URL |
OpenTelemetry SDK for Java へのカスタムサンプラーの登録
手動でインストルメンテーションを行うアプリケーションの場合は、サンプラーを直接アプリケーションコードに追加します。
前提条件
開始する前に、以下を確認してください:
OpenTelemetry SDK for Java で手動でインストルメンテーションされたアプリケーション。セットアップ手順については、「Java アプリケーションのトレースデータを OpenTelemetry を使用して送信する」をご参照ください。
ステップ 1: サンプラークラスの作成
SpanFilterSampler クラスを作成し、Sampler インターフェイスを実装します。実装は、「ステップ 3: サンプラーの実装」のエージェント拡張サンプラーと同じです。ドロップしたいスパンに合わせて EXCLUDED_SPAN_NAMES および EXCLUDED_HTTP_REQUEST_TARGETS リストを調整します。
ステップ 2: SdkTracerProvider へのサンプラーの登録
SdkTracerProvider インスタンスをビルドする際に .setSampler(new SpanFilterSampler()) を呼び出します:
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.setSampler(new SpanFilterSampler()) // カスタムサンプラーの登録
.addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder()
.setEndpoint("<endpoint>")
.addHeader("Authentication", "<token>")
.build()).build())
.setResource(resource)
.build();ステップ 3: アプリケーションの再起動
アプリケーションを再起動します。サンプラーはすべての新しいスパンを評価し、フィルターのルールに一致するものをドロップします。
Node.js
デモプロジェクト: opentelemetry-nodejs-demo
前提条件
開始する前に、以下を確認してください:
OpenTelemetry 向けマネージドサービスの JavaScript 用 API でインストルメンテーションされたアプリケーション。セットアップ手順については、「OpenTelemetry を使用して Node.js アプリケーションのトレースデータを送信する」をご参照ください。
作成時のスパンのフィルタリング
HttpInstrumentation で ignoreIncomingRequestHook を構成することで、特定の HTTP リクエストがスパンを生成しないようにします。このフックはリクエスト処理の前に実行され、スパンが作成されるかどうかのみを制御します。リクエスト自体は通常どおり処理されます。
次の例では、/api/checkHealth へのリクエストのスパン作成をスキップします:
const httpInstrumentation = new HttpInstrumentation({
ignoreIncomingRequestHook: (request) => {
// ヘルスチェックリクエストのスパン作成をスキップ
if (request.url === '/api/checkHealth') {
return true;
}
return false;
},
});
registerInstrumentations({
tracerProvider: provider,
instrumentations: [httpInstrumentation, ExpressInstrumentation],
});インストルメンテーションの構成を更新した後、アプリケーションを起動します。
エクスポート時のスパンのフィルタリング
カスタムサンプラーを実装することで、作成後に属性に基づいてスパンをドロップします。
ステップ 1: サンプラークラスの作成
Sampler インターフェイスを実装するクラスを作成します。shouldSample でフィルタリングロジックを定義します:
const opentelemetry = require('@opentelemetry/api');
class SpanFilterSampler {
shouldSample(spanContext, parentContext) {
// ここにカスタムサンプリングロジックを実装します。
}
}ステップ 2: NodeTracerProvider へのサンプラーの登録
サンプラーインスタンスを NodeTracerProvider コンストラクターに渡します:
const provider = new NodeTracerProvider({
sampler: new SpanFilterSampler(), // カスタムサンプラーの登録
resource: new Resource({
[SemanticResourceAttributes.HOST_NAME]: require("os").hostname(),
[SemanticResourceAttributes.SERVICE_NAME]: "<your-service-name>",
}),
});<your-service-name> を、my-node-app のように、ご利用のサービス名に置き換えます。
プロバイダーの構成を更新した後、アプリケーションを起動します。
フィルタリングが機能することの確認
カスタムサンプラーを構成してデプロイした後、スパンが正しくフィルタリングされていることを確認します:
フィルターのルールに一致するトラフィックを生成します。たとえば、
/api/checkHealthやその他のフィルタリングされたエンドポイントにリクエストを送信します。OpenTelemetry 向けマネージドサービスのコンソールを開きます。フィルタリングされたスパンは、トレースに表示されなくなります。
フィルタリング前後のスパン数を比較します。フィルタリングされたエンドポイントのスパンボリュームが減少していれば、サンプラーが機能していることが確認できます。
フィルタリングされたスパンがまだ表示される場合は、以下を確認してください:
| 現象 | 考えられる原因 | 解決策 |
|---|---|---|
| スパンがまだエクスポートされる | サンプラーが登録されていない | OTEL_TRACES_SAMPLER または -Dotel.traces.sampler がサンプラー名に設定されていることを確認します |
| 起動時にサンプラーが見つからないエラー | 名前の不一致 | プロバイダーの getName() が、起動パラメーターで使用されているのと同じ名前を返すことを確認します |
| 拡張 JAR がロードされない | パスが正しくない | OTEL_JAVAAGENT_EXTENSIONS または -Dotel.javaagent.extensions のパスが正しい JAR ファイルを指していることを確認します |
| 誤ったスパンがフィルタリングされる | フィルターのルールの論理エラー | shouldSample の条件を確認し、スパン名と属性値が期待どおりであることを確認します |