SDKによるテレメトリーの管理

SDKは、計装API呼び出しによって生成されたテレメトリーを処理およびエクスポートするAPIの組み込み参照実装です。 このページは、説明、関連するJavadocへのリンク、アーティファクト座標、サンプルプログラム設定などを含むSDKの概念的な概要です。 ゼロコードSDK自動設定を含むSDK設定の詳細については、**SDKの設定**を参照してください。

SDKは以下のトップレベルコンポーネントで構成されています。

  • SdkTracerProviderTracerProviderのSDK実装で、スパンのサンプリング、処理、エクスポートのためのツールを含みます
  • SdkMeterProviderMeterProviderのSDK実装で、メトリクスストリームの設定とメトリクスの読み取り/エクスポートのためのツールを含みます
  • SdkLoggerProviderLoggerProviderのSDK実装で、ログの処理とエクスポートのためのツールを含みます
  • TextMapPropagator:プロセス境界を越えてコンテキストを伝播します

これらはOpenTelemetrySdkに結合され、完全に設定されたSDKコンポーネントを計装に渡すのに便利なキャリアオブジェクトです。

SDKには多くの使用例に十分な様々な組み込みコンポーネントがパッケージ化されており、拡張性のためのプラグインインターフェースをサポートしています。

SDKプラグイン拡張インターフェース

組み込みコンポーネントが不十分な場合、さまざまなプラグイン拡張インターフェースを実装することでSDKを拡張できます。

  • Sampler:記録およびサンプリングされるスパンを設定します
  • SpanProcessor:スパンの開始時と終了時に処理します
  • SpanExporter:スパンをプロセス外にエクスポートします
  • MetricReader:集約されたメトリクスを読み取ります
  • MetricExporter:メトリクスをプロセス外にエクスポートします
  • LogRecordProcessor:ログレコードの発行時に処理します
  • LogRecordExporter:ログレコードをプロセス外にエクスポートします
  • TextMapPropagator:プロセス境界を越えてコンテキストを伝播します

SDKコンポーネント

io.opentelemetry:opentelemetry-sdk:1.50.0 アーティファクトにはOpenTelemetry SDKが含まれています。

以下のセクションでは、SDKのコアユーザー向けコンポーネントについて説明します。各コンポーネントセクションには以下が含まれます。

OpenTelemetrySdk

OpenTelemetrySdkOpenTelemetryのSDK実装です。 これは、完全に設定されたSDKコンポーネントを計装に渡すのに便利なトップレベルSDKコンポーネントのホルダーです。

OpenTelemetrySdkはアプリケーション所有者によって設定され、以下で構成されています。

以下のコードスニペットはOpenTelemetrySdkのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;

public class OpenTelemetrySdkConfig {
  public static OpenTelemetrySdk create() {
    Resource resource = ResourceConfig.create();
    return OpenTelemetrySdk.builder()
        .setTracerProvider(SdkTracerProviderConfig.create(resource))
        .setMeterProvider(SdkMeterProviderConfig.create(resource))
        .setLoggerProvider(SdkLoggerProviderConfig.create(resource))
        .setPropagators(ContextPropagatorsConfig.create())
        .build();
  }
}

Resource

Resourceは、テレメトリーソースを定義する属性のセットです。 アプリケーションは、SdkTracerProviderSdkMeterProviderSdkLoggerProviderと同じリソースを関連付ける必要があります。

以下のコードスニペットはResourceのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.ServiceAttributes;

public class ResourceConfig {
  public static Resource create() {
    return Resource.getDefault().toBuilder()
        .put(ServiceAttributes.SERVICE_NAME, "my-service")
        .build();
  }
}

SdkTracerProvider

SdkTracerProviderTracerProviderのSDK実装で、APIによって生成されたトレーステレメトリーの処理を担当します。

SdkTracerProviderはアプリケーション所有者によって設定され、以下で構成されています。

  • Resource:スパンが関連付けられるリソース
  • Sampler:記録およびサンプリングされるスパンを設定します
  • SpanProcessors:スパンの開始時と終了時に処理します
  • SpanExporters:スパンをプロセス外にエクスポートします(関連するSpanProcessorと連携して)
  • SpanLimits:スパンに関連付けられるデータの制限を制御します

以下のコードスニペットはSdkTracerProviderのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;

public class SdkTracerProviderConfig {
  public static SdkTracerProvider create(Resource resource) {
    return SdkTracerProvider.builder()
        .setResource(resource)
        .addSpanProcessor(
            SpanProcessorConfig.batchSpanProcessor(
                SpanExporterConfig.otlpHttpSpanExporter("http://localhost:4318/v1/spans")))
        .setSampler(SamplerConfig.parentBasedSampler(SamplerConfig.traceIdRatioBased(.25)))
        .setSpanLimits(SpanLimitsConfig::spanLimits)
        .build();
  }
}

Sampler

Samplerは、記録およびサンプリングされるスパンを決定する責任を持つプラグイン拡張インターフェースです。

SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているサンプラー。

クラスアーティファクト説明
ParentBasedio.opentelemetry:opentelemetry-sdk:1.50.0スパンの親のサンプリングステータスに基づいてスパンをサンプリングします。
AlwaysOnio.opentelemetry:opentelemetry-sdk:1.50.0すべてのスパンをサンプリングします。
AlwaysOffio.opentelemetry:opentelemetry-sdk:1.50.0すべてのスパンをドロップします。
TraceIdRatioBasedio.opentelemetry:opentelemetry-sdk:1.50.0設定可能な比率に基づいてスパンをサンプリングします。
JaegerRemoteSamplerio.opentelemetry:opentelemetry-sdk-extension-jaeger-remote-sampler:1.50.0リモートサーバーからの設定に基づいてスパンをサンプリングします。
LinksBasedSamplerio.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alphaスパンのリンクのサンプリングステータスに基づいてスパンをサンプリングします。
RuleBasedRoutingSamplerio.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alpha設定可能なルールに基づいてスパンをサンプリングします。
ConsistentSamplersio.opentelemetry.contrib:opentelemetry-consistent-sampling:1.46.0-alpha確率サンプリングで定義されたさまざまな一貫性のあるサンプラー実装。

以下のコードスニペットはSamplerのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import java.time.Duration;

public class SamplerConfig {
  public static Sampler parentBasedSampler(Sampler root) {
    return Sampler.parentBasedBuilder(root)
        .setLocalParentNotSampled(Sampler.alwaysOff())
        .setLocalParentSampled(Sampler.alwaysOn())
        .setRemoteParentNotSampled(Sampler.alwaysOff())
        .setRemoteParentSampled(Sampler.alwaysOn())
        .build();
  }

  public static Sampler alwaysOn() {
    return Sampler.alwaysOn();
  }

  public static Sampler alwaysOff() {
    return Sampler.alwaysOff();
  }

  public static Sampler traceIdRatioBased(double ratio) {
    return Sampler.traceIdRatioBased(ratio);
  }

  public static Sampler jaegerRemoteSampler() {
    return JaegerRemoteSampler.builder()
        .setInitialSampler(Sampler.alwaysOn())
        .setEndpoint("http://endpoint")
        .setPollingInterval(Duration.ofSeconds(60))
        .setServiceName("my-service-name")
        .build();
  }
}

独自のカスタムサンプリングロジックを提供するには、Samplerインターフェースを実装してください。 例を挙げましょう。

package otel;

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.SamplingResult;
import java.util.List;

public class CustomSampler implements Sampler {
  @Override
  public SamplingResult shouldSample(
      Context parentContext,
      String traceId,
      String name,
      SpanKind spanKind,
      Attributes attributes,
      List<LinkData> parentLinks) {
    // スパンが開始されたときに呼び出されるコールバック(SpanProcessorが呼び出される前)。
    // SamplingDecisionが:
    // - DROP: スパンがドロップされます。有効なスパンコンテキストが作成され、SpanProcessor#onStartは
    // まだ呼び出されますが、データは記録されず、SpanProcessor#onEndは呼び出されません。
    // - RECORD_ONLY: スパンは記録されますがサンプリングされません。データはスパンに記録され、
    // SpanProcessor#onStartとSpanProcessor#onEndが呼び出されますが、スパンのサンプリングステータスは
    // プロセス外にエクスポートされるべきではないことを示します。
    // - RECORD_AND_SAMPLE: スパンは記録およびサンプリングされます。データはスパンに記録され、
    // SpanProcessor#onStartとSpanProcessor#onEndが呼び出され、スパンのサンプリングステータスは
    // プロセス外にエクスポートされるべきであることを示します。
    return SpanKind.SERVER == spanKind ? SamplingResult.recordAndSample() : SamplingResult.drop();
  }

  @Override
  public String getDescription() {
    // サンプラーの説明を返します。
    return this.getClass().getSimpleName();
  }
}

SpanProcessor

SpanProcessorは、スパンが開始および終了されたときに呼び出されるコールバックを持つプラグイン拡張インターフェースです。 これらはしばしばSpanExportersと組み合わせてスパンをプロセス外にエクスポートしますが、データエンリッチメントなどの他の用途もあります。

SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているスパンプロセッサー。

クラスアーティファクト説明
BatchSpanProcessorio.opentelemetry:opentelemetry-sdk:1.50.0サンプリングされたスパンをバッチ処理し、設定可能なSpanExporterを介してエクスポートします。
SimpleSpanProcessorio.opentelemetry:opentelemetry-sdk:1.50.0各サンプリングされたスパンを設定可能なSpanExporterを介してエクスポートします。
BaggageSpanProcessorio.opentelemetry.contrib:opentelemetry-baggage-processor:1.46.0-alphaスパンをバゲージでエンリッチします。
JfrSpanProcessorio.opentelemetry.contrib:opentelemetry-jfr-events:1.46.0-alphaスパンからJFRイベントを作成します。
StackTraceSpanProcessorio.opentelemetry.contrib:opentelemetry-span-stacktrace:1.46.0-alpha選択されたスパンをスタックトレースデータでエンリッチします。
InferredSpansProcessorio.opentelemetry.contrib:opentelemetry-inferred-spans:1.46.0-alpha計装ではなく非同期プロファイラーからスパンを生成します。

以下のコードスニペットはSpanProcessorのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.time.Duration;

public class SpanProcessorConfig {
  public static SpanProcessor batchSpanProcessor(SpanExporter spanExporter) {
    return BatchSpanProcessor.builder(spanExporter)
        .setMaxQueueSize(2048)
        .setExporterTimeout(Duration.ofSeconds(30))
        .setScheduleDelay(Duration.ofSeconds(5))
        .build();
  }

  public static SpanProcessor simpleSpanProcessor(SpanExporter spanExporter) {
    return SimpleSpanProcessor.builder(spanExporter).build();
  }
}

独自のカスタムスパン処理ロジックを提供するには、SpanProcessorインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;

public class CustomSpanProcessor implements SpanProcessor {

  @Override
  public void onStart(Context parentContext, ReadWriteSpan span) {
    // スパンが開始されたときに呼び出されるコールバック。
    // カスタム属性でレコードをエンリッチします。
    span.setAttribute("my.custom.attribute", "hello world");
  }

  @Override
  public boolean isStartRequired() {
    // onStartが呼び出されるべきかどうかを示します。
    return true;
  }

  @Override
  public void onEnd(ReadableSpan span) {
    // スパンが終了されたときに呼び出されるコールバック。
  }

  @Override
  public boolean isEndRequired() {
    // onEndが呼び出されるべきかどうかを示します。
    return false;
  }

  @Override
  public CompletableResultCode shutdown() {
    // オプションでプロセッサーをシャットダウンし、リソースをクリーンアップします。
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode forceFlush() {
    // オプションでキューに入れられているがまだ処理されていないレコードを処理します。
    return CompletableResultCode.ofSuccess();
  }
}

SpanExporter

SpanExporterは、スパンをプロセス外にエクスポートする責任を持つプラグイン拡張インターフェースです。 SdkTracerProviderに直接登録するのではなく、SpanProcessors(通常はBatchSpanProcessor)と組み合わせます。

SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているスパンエクスポーター。

クラスアーティファクト説明
OtlpHttpSpanExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.50.0OTLP http/protobufを介してスパンをエクスポートします。
OtlpGrpcSpanExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.50.0OTLP grpcを介してスパンをエクスポートします。
LoggingSpanExporterio.opentelemetry:opentelemetry-exporter-logging:1.50.0スパンをデバッグ形式でJULにログ出力します。
OtlpJsonLoggingSpanExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.50.0スパンをOTLP JSONエンコーディングでJULにログ出力します。
OtlpStdoutSpanExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.50.0スパンをOTLP JSONファイルエンコーディング(実験的)でSystem.outにログ出力します。
ZipkinSpanExporterio.opentelemetry:opentelemetry-exporter-zipkin:1.50.0スパンをZipkinにエクスポートします。
InterceptableSpanExporterio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaエクスポート前にスパンを柔軟なインターセプターに渡します。
KafkaSpanExporterio.opentelemetry.contrib:opentelemetry-kafka-exporter:1.46.0-alphaKafkaトピックに書き込むことでスパンをエクスポートします。

[1]: 実装の詳細についてはOTLPエクスポーターを参照してください。

以下のコードスニペットはSpanExporterのプログラム設定を示します。

package otel;

import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingSpanExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.time.Duration;

public class SpanExporterConfig {
  public static SpanExporter otlpHttpSpanExporter(String endpoint) {
    return OtlpHttpSpanExporter.builder()
        .setEndpoint(endpoint)
        .addHeader("api-key", "value")
        .setTimeout(Duration.ofSeconds(10))
        .build();
  }

  public static SpanExporter otlpGrpcSpanExporter(String endpoint) {
    return OtlpGrpcSpanExporter.builder()
        .setEndpoint(endpoint)
        .addHeader("api-key", "value")
        .setTimeout(Duration.ofSeconds(10))
        .build();
  }

  public static SpanExporter logginSpanExporter() {
    return LoggingSpanExporter.create();
  }

  public static SpanExporter otlpJsonLoggingSpanExporter() {
    return OtlpJsonLoggingSpanExporter.create();
  }
}

独自のカスタムスパンエクスポートロジックを提供するには、SpanExporterインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CustomSpanExporter implements SpanExporter {

  private static final Logger logger = Logger.getLogger(CustomSpanExporter.class.getName());

  @Override
  public CompletableResultCode export(Collection<SpanData> spans) {
    // レコードをエクスポートします。通常、レコードは何らかのネットワークプロトコルを介してプロセス外に送信されますが、
    // 説明のためにここでは単にログ出力します。
    logger.log(Level.INFO, "Exporting spans");
    spans.forEach(span -> logger.log(Level.INFO, "Span: " + span));
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode flush() {
    // キューに入れられているがまだエクスポートされていないレコードをエクスポートします。
    logger.log(Level.INFO, "flushing");
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode shutdown() {
    // エクスポーターをシャットダウンし、リソースをクリーンアップします。
    logger.log(Level.INFO, "shutting down");
    return CompletableResultCode.ofSuccess();
  }
}

SpanLimits

SpanLimitsは、最大属性長、最大属性数などを含む、スパンによってキャプチャされるデータの制約を定義します。

以下のコードスニペットはSpanLimitsのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.trace.SpanLimits;

public class SpanLimitsConfig {
  public static SpanLimits spanLimits() {
    return SpanLimits.builder()
        .setMaxNumberOfAttributes(128)
        .setMaxAttributeValueLength(1024)
        .setMaxNumberOfLinks(128)
        .setMaxNumberOfAttributesPerLink(128)
        .setMaxNumberOfEvents(128)
        .setMaxNumberOfAttributesPerEvent(128)
        .build();
  }
}

SdkMeterProvider

SdkMeterProviderMeterProviderのSDK実装で、APIによって生成されたメトリクステレメトリーの処理を担当します。

SdkMeterProviderはアプリケーション所有者によって設定され、以下で構成されています。

  • Resource:メトリクスが関連付けられるリソース
  • MetricReader:メトリクスの集約状態を読み取ります
    • オプションで、計装種別ごとのカーディナリティ制限をオーバーライドするためのCardinalityLimitSelector。設定されていない場合、各計装は収集サイクルごとに2000の一意の属性組み合わせに制限されます。カーディナリティ制限はビューを介して個々の計装でも設定可能です。詳細についてはカーディナリティ制限を参照してください
  • MetricExporter:メトリクスをプロセス外にエクスポートします(関連するMetricReaderと連携して)
  • Views:未使用メトリクスのドロップを含む、メトリクスストリームを設定します

以下のコードスニペットはSdkMeterProviderのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.resources.Resource;
import java.util.List;
import java.util.Set;

public class SdkMeterProviderConfig {
  public static SdkMeterProvider create(Resource resource) {
    SdkMeterProviderBuilder builder =
        SdkMeterProvider.builder()
            .setResource(resource)
            .registerMetricReader(
                MetricReaderConfig.periodicMetricReader(
                    MetricExporterConfig.otlpHttpMetricExporter(
                        "http://localhost:4318/v1/metrics")));
    // カーディナリティ制限付きでメトリクスリーダーを登録するオプションのコメントアウト解除
    // builder.registerMetricReader(
    //     MetricReaderConfig.periodicMetricReader(
    //         MetricExporterConfig.otlpHttpMetricExporter("http://localhost:4318/v1/metrics")),
    //     instrumentType -> 100);

    ViewConfig.dropMetricView(builder, "some.custom.metric");
    ViewConfig.histogramBucketBoundariesView(
        builder, "http.server.request.duration", List.of(1.0, 5.0, 10.0));
    ViewConfig.attributeFilterView(
        builder, "http.client.request.duration", Set.of("http.request.method"));
    ViewConfig.cardinalityLimitsView(builder, "http.server.active_requests", 100);
    return builder.build();
  }
}

MetricReader

MetricReaderは、集約されたメトリクスを読み取る責任を持つプラグイン拡張インターフェースです。 これらはしばしばMetricExportersと組み合わせてメトリクスをプロセス外にエクスポートしますが、プルベースプロトコルで外部スクレイパーにメトリクスを提供するためにも使用される場合があります。

下表は、SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているメトリクスリーダーです。

クラスアーティファクト説明
PeriodicMetricReaderio.opentelemetry:opentelemetry-sdk:1.50.0定期的にメトリクスを読み取り、設定可能なMetricExporterを介してエクスポートします。
PrometheusHttpServerio.opentelemetry:opentelemetry-exporter-prometheus:1.50.0-alphaさまざまなprometheus形式でHTTPサーバー上でメトリクスを提供します。

以下のコードスニペットはMetricReaderのプログラム設定を示します。

package otel;

import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import java.time.Duration;

public class MetricReaderConfig {
  public static MetricReader periodicMetricReader(MetricExporter metricExporter) {
    return PeriodicMetricReader.builder(metricExporter).setInterval(Duration.ofSeconds(60)).build();
  }

  public static MetricReader prometheusMetricReader() {
    return PrometheusHttpServer.builder().setHost("localhost").setPort(9464).build();
  }
}

独自のカスタムメトリクスリーダーロジックを提供するには、MetricReaderインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CustomMetricReader implements MetricReader {

  private static final Logger logger = Logger.getLogger(CustomMetricExporter.class.getName());

  private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
  private final AtomicReference<CollectionRegistration> collectionRef =
      new AtomicReference<>(CollectionRegistration.noop());

  @Override
  public void register(CollectionRegistration collectionRegistration) {
    // SdkMeterProviderが初期化されたときに呼び出されるコールバックで、メトリクスを収集するハンドルを提供します。
    collectionRef.set(collectionRegistration);
    executorService.scheduleWithFixedDelay(this::collectMetrics, 0, 60, TimeUnit.SECONDS);
  }

  private void collectMetrics() {
    // メトリクスを収集します。通常、レコードは何らかのネットワークプロトコルを介してプロセス外に送信されますが、
    // 説明のためにここでは単にログ出力します。
    logger.log(Level.INFO, "Collecting metrics");
    collectionRef
        .get()
        .collectAllMetrics()
        .forEach(metric -> logger.log(Level.INFO, "Metric: " + metric));
  }

  @Override
  public CompletableResultCode forceFlush() {
    // キューに入れられているがまだエクスポートされていないレコードをエクスポートします。
    logger.log(Level.INFO, "flushing");
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode shutdown() {
    // エクスポーターをシャットダウンし、リソースをクリーンアップします。
    logger.log(Level.INFO, "shutting down");
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) {
    // InstrumentTypeの関数として必要な集約時間性を指定
    return AggregationTemporalitySelector.deltaPreferred()
        .getAggregationTemporality(instrumentType);
  }

  @Override
  public MemoryMode getMemoryMode() {
    // オプションでメモリモードを指定し、メトリクスレコードが再利用可能か不変である必要があるかを示します
    return MemoryMode.REUSABLE_DATA;
  }

  @Override
  public Aggregation getDefaultAggregation(InstrumentType instrumentType) {
    // オプションで計装種別の関数としてデフォルト集約を指定
    return Aggregation.defaultAggregation();
  }
}

MetricExporter

MetricExporterは、メトリクスをプロセス外にエクスポートする責任を持つプラグイン拡張インターフェースです。 SdkMeterProviderに直接登録するのではなく、PeriodicMetricReaderと組み合わせます。

SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているメトリクスエクスポーター。

クラスアーティファクト説明
OtlpHttpMetricExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.50.0OTLP http/protobufを介してメトリクスをエクスポートします。
OtlpGrpcMetricExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.50.0OTLP grpcを介してメトリクスをエクスポートします。
LoggingMetricExporterio.opentelemetry:opentelemetry-exporter-logging:1.50.0メトリクスをデバッグ形式でJULにログ出力します。
OtlpJsonLoggingMetricExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.50.0メトリクスをOTLP JSONエンコーディングでJULにログ出力します。
OtlpStdoutMetricExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.50.0メトリクスをOTLP JSONファイルエンコーディング(実験的)でSystem.outにログ出力します。
InterceptableMetricExporterio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaエクスポート前にメトリクスを柔軟なインターセプターに渡します。

[1]: 実装の詳細についてはOTLPエクスポーターを参照してください。

以下のコードスニペットはMetricExporterのプログラム設定を示します。

package otel;

import io.opentelemetry.exporter.logging.LoggingMetricExporter;
import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import java.time.Duration;

public class MetricExporterConfig {
  public static MetricExporter otlpHttpMetricExporter(String endpoint) {
    return OtlpHttpMetricExporter.builder()
        .setEndpoint(endpoint)
        .addHeader("api-key", "value")
        .setTimeout(Duration.ofSeconds(10))
        .build();
  }

  public static MetricExporter otlpGrpcMetricExporter(String endpoint) {
    return OtlpGrpcMetricExporter.builder()
        .setEndpoint(endpoint)
        .addHeader("api-key", "value")
        .setTimeout(Duration.ofSeconds(10))
        .build();
  }

  public static MetricExporter logginMetricExporter() {
    return LoggingMetricExporter.create();
  }

  public static MetricExporter otlpJsonLoggingMetricExporter() {
    return OtlpJsonLoggingMetricExporter.create();
  }
}

独自のカスタムメトリクスエクスポートロジックを提供するには、MetricExporterインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CustomMetricExporter implements MetricExporter {

  private static final Logger logger = Logger.getLogger(CustomMetricExporter.class.getName());

  @Override
  public CompletableResultCode export(Collection<MetricData> metrics) {
    // レコードをエクスポートします。通常、レコードは何らかのネットワークプロトコルを介してプロセス外に送信されますが、
    // 説明のためにここでは単にログ出力します。
    logger.log(Level.INFO, "Exporting metrics");
    metrics.forEach(metric -> logger.log(Level.INFO, "Metric: " + metric));
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode flush() {
    // キューに入れられているがまだエクスポートされていないレコードをエクスポートします。
    logger.log(Level.INFO, "flushing");
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode shutdown() {
    // エクスポーターをシャットダウンし、リソースをクリーンアップします。
    logger.log(Level.INFO, "shutting down");
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) {
    // 計装種別の関数として必要な集約時間性を指定
    return AggregationTemporalitySelector.deltaPreferred()
        .getAggregationTemporality(instrumentType);
  }

  @Override
  public MemoryMode getMemoryMode() {
    // オプションでメモリモードを指定し、メトリクスレコードが再利用可能か不変である必要があるかを示します
    return MemoryMode.REUSABLE_DATA;
  }

  @Override
  public Aggregation getDefaultAggregation(InstrumentType instrumentType) {
    // オプションで計装種別の関数としてデフォルト集約を指定
    return Aggregation.defaultAggregation();
  }
}

Views

Viewsは、メトリクス名の変更、メトリクス説明、メトリクス集約(ヒストグラムバケット境界など)、保持する属性キーのセット、カーディナリティ制限などを含む、メトリクスストリームのカスタマイズを可能にします。

以下のコードスニペットはViewのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.View;
import java.util.List;
import java.util.Set;

public class ViewConfig {
  public static SdkMeterProviderBuilder dropMetricView(
      SdkMeterProviderBuilder builder, String metricName) {
    return builder.registerView(
        InstrumentSelector.builder().setName(metricName).build(),
        View.builder().setAggregation(Aggregation.drop()).build());
  }

  public static SdkMeterProviderBuilder histogramBucketBoundariesView(
      SdkMeterProviderBuilder builder, String metricName, List<Double> bucketBoundaries) {
    return builder.registerView(
        InstrumentSelector.builder().setName(metricName).build(),
        View.builder()
            .setAggregation(Aggregation.explicitBucketHistogram(bucketBoundaries))
            .build());
  }

  public static SdkMeterProviderBuilder attributeFilterView(
      SdkMeterProviderBuilder builder, String metricName, Set<String> keysToRetain) {
    return builder.registerView(
        InstrumentSelector.builder().setName(metricName).build(),
        View.builder().setAttributeFilter(keysToRetain).build());
  }

  public static SdkMeterProviderBuilder cardinalityLimitsView(
      SdkMeterProviderBuilder builder, String metricName, int cardinalityLimit) {
    return builder.registerView(
        InstrumentSelector.builder().setName(metricName).build(),
        View.builder().setCardinalityLimit(cardinalityLimit).build());
  }
}

SdkLoggerProvider

SdkLoggerProviderLoggerProviderのSDK実装で、ログブリッジAPIによって生成されたログテレメトリーの処理を担当します。

SdkLoggerProviderはアプリケーション所有者によって設定され、以下で構成されています。

  • Resource:ログが関連付けられるリソース
  • LogRecordProcessor:ログの発行時に処理します
  • LogRecordExporter:ログをプロセス外にエクスポートします(関連するLogRecordProcessorと連携して)
  • LogLimits:ログに関連付けられるデータの制限を制御します

以下のコードスニペットはSdkLoggerProviderのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.resources.Resource;

public class SdkLoggerProviderConfig {
  public static SdkLoggerProvider create(Resource resource) {
    return SdkLoggerProvider.builder()
        .setResource(resource)
        .addLogRecordProcessor(
            LogRecordProcessorConfig.batchLogRecordProcessor(
                LogRecordExporterConfig.otlpHttpLogRecordExporter("http://localhost:4318/v1/logs")))
        .setLogLimits(LogLimitsConfig::logLimits)
        .build();
  }
}

LogRecordProcessor

LogRecordProcessorは、ログが発行されたときに呼び出されるコールバックを持つプラグイン拡張インターフェースです。 これらはしばしばLogRecordExportersと組み合わせてログをプロセス外にエクスポートしますが、データエンリッチメントなどの他の用途もあります。

下表は、SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているログレコードプロセッサーです。

クラスアーティファクト説明
BatchLogRecordProcessorio.opentelemetry:opentelemetry-sdk:1.50.0ログレコードをバッチ処理し、設定可能なLogRecordExporterを介してエクスポートします。
SimpleLogRecordProcessorio.opentelemetry:opentelemetry-sdk:1.50.0各ログレコードを設定可能なLogRecordExporterを介してエクスポートします。
EventToSpanEventBridgeio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaイベントログレコードを現在のスパンのスパンイベントとして記録します。

以下のコードスニペットはLogRecordProcessorのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.logs.LogRecordProcessor;
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor;
import java.time.Duration;

public class LogRecordProcessorConfig {
  public static LogRecordProcessor batchLogRecordProcessor(LogRecordExporter logRecordExporter) {
    return BatchLogRecordProcessor.builder(logRecordExporter)
        .setMaxQueueSize(2048)
        .setExporterTimeout(Duration.ofSeconds(30))
        .setScheduleDelay(Duration.ofSeconds(1))
        .build();
  }

  public static LogRecordProcessor simpleLogRecordProcessor(LogRecordExporter logRecordExporter) {
    return SimpleLogRecordProcessor.create(logRecordExporter);
  }
}

独自のカスタムログ処理ロジックを提供するには、LogRecordProcessorインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.logs.LogRecordProcessor;
import io.opentelemetry.sdk.logs.ReadWriteLogRecord;

public class CustomLogRecordProcessor implements LogRecordProcessor {

  @Override
  public void onEmit(Context context, ReadWriteLogRecord logRecord) {
    // ログレコードが発行されたときに呼び出されるコールバック。
    // カスタム属性でレコードをエンリッチします。
    logRecord.setAttribute(AttributeKey.stringKey("my.custom.attribute"), "hello world");
  }

  @Override
  public CompletableResultCode shutdown() {
    // オプションでプロセッサーをシャットダウンし、リソースをクリーンアップします。
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode forceFlush() {
    // オプションでキューに入れられているがまだ処理されていないレコードを処理します。
    return CompletableResultCode.ofSuccess();
  }
}

LogRecordExporter

LogRecordExporterは、ログレコードをプロセス外にエクスポートする責任を持つプラグイン拡張インターフェースです。 SdkLoggerProviderに直接登録するのではなく、LogRecordProcessors(通常はBatchLogRecordProcessor)と組み合わせます。

下表は、SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているスパンエクスポーターです。

クラスアーティファクト説明
OtlpHttpLogRecordExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.50.0OTLP http/protobufを介してログレコードをエクスポートします。
OtlpGrpcLogRecordExporter [1]io.opentelemetry:opentelemetry-exporter-otlp:1.50.0OTLP grpcを介してログレコードをエクスポートします。
SystemOutLogRecordExporterio.opentelemetry:opentelemetry-exporter-logging:1.50.0ログレコードをデバッグ形式でsystem outにログ出力します。
OtlpJsonLoggingLogRecordExporter [2]io.opentelemetry:opentelemetry-exporter-logging-otlp:1.50.0ログレコードをOTLP JSONエンコーディングでJULにログ出力します。
OtlpStdoutLogRecordExporterio.opentelemetry:opentelemetry-exporter-logging-otlp:1.50.0ログレコードをOTLP JSONファイルエンコーディング(実験的)でSystem.outにログ出力します。
InterceptableLogRecordExporterio.opentelemetry.contrib:opentelemetry-processors:1.46.0-alphaエクスポート前にログレコードを柔軟なインターセプターに渡します。

[1]: 実装の詳細についてはOTLPエクスポーターを参照してください。

[2]: OtlpJsonLoggingLogRecordExporterはJULにログ出力し、適切に設定されていない場合、無限ループ(JUL -> SLF4J -> Logback -> OpenTelemetry Appender -> OpenTelemetry Log SDK -> JUL)を引き起こす可能性があります。

以下のコードスニペットはLogRecordProcessorのプログラム設定を示します。

package otel;

import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter;
import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingLogRecordExporter;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import java.time.Duration;

public class LogRecordExporterConfig {
  public static LogRecordExporter otlpHttpLogRecordExporter(String endpoint) {
    return OtlpHttpLogRecordExporter.builder()
        .setEndpoint(endpoint)
        .addHeader("api-key", "value")
        .setTimeout(Duration.ofSeconds(10))
        .build();
  }

  public static LogRecordExporter otlpGrpcLogRecordExporter(String endpoint) {
    return OtlpGrpcLogRecordExporter.builder()
        .setEndpoint(endpoint)
        .addHeader("api-key", "value")
        .setTimeout(Duration.ofSeconds(10))
        .build();
  }

  public static LogRecordExporter systemOutLogRecordExporter() {
    return SystemOutLogRecordExporter.create();
  }

  public static LogRecordExporter otlpJsonLoggingLogRecordExporter() {
    return OtlpJsonLoggingLogRecordExporter.create();
  }
}

独自のカスタムログレコードエクスポートロジックを提供するには、LogRecordExporterインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.logs.data.LogRecordData;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CustomLogRecordExporter implements LogRecordExporter {

  private static final Logger logger = Logger.getLogger(CustomLogRecordExporter.class.getName());

  @Override
  public CompletableResultCode export(Collection<LogRecordData> logs) {
    // レコードをエクスポートします。通常、レコードは何らかのネットワークプロトコルを介してプロセス外に送信されますが、
    // 説明のためにここでは単にログ出力します。
    System.out.println("Exporting logs");
    logs.forEach(log -> System.out.println("log record: " + log));
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode flush() {
    // キューに入れられているがまだエクスポートされていないレコードをエクスポートします。
    logger.log(Level.INFO, "flushing");
    return CompletableResultCode.ofSuccess();
  }

  @Override
  public CompletableResultCode shutdown() {
    // エクスポーターをシャットダウンし、リソースをクリーンアップします。
    logger.log(Level.INFO, "shutting down");
    return CompletableResultCode.ofSuccess();
  }
}

LogLimits

LogLimitsは、最大属性長や最大属性数を含む、ログレコードによってキャプチャされるデータの制約を定義します。

以下のコードスニペットはLogRecordProcessorのプログラム設定を示します。

package otel;

import io.opentelemetry.sdk.logs.LogLimits;

public class LogLimitsConfig {
  public static LogLimits logLimits() {
    return LogLimits.builder()
        .setMaxNumberOfAttributes(128)
        .setMaxAttributeValueLength(1024)
        .build();
  }
}

TextMapPropagator

TextMapPropagatorは、テキスト形式でプロセス境界を越えてコンテキストを伝播する責任を持つプラグイン拡張インターフェースです。

SDKに組み込まれ、opentelemetry-java-contribでコミュニティによって維持されているTextMapPropagators。

クラスアーティファクト説明
W3CTraceContextPropagatorio.opentelemetry:opentelemetry-api:1.50.0W3Cトレースコンテキスト伝播プロトコルを使用してトレースコンテキストを伝播します。
W3CBaggagePropagatorio.opentelemetry:opentelemetry-api:1.50.0W3Cバゲージ伝播プロトコルを使用してバゲージを伝播します。
MultiTextMapPropagatorio.opentelemetry:opentelemetry-context:1.50.0複数のプロパゲーターを構成します。
JaegerPropagatorio.opentelemetry:opentelemetry-extension-trace-propagators:1.50.0Jaeger伝播プロトコルを使用してトレースコンテキストを伝播します。
B3Propagatorio.opentelemetry:opentelemetry-extension-trace-propagators:1.50.0B3伝播プロトコルを使用してトレースコンテキストを伝播します。
OtTracePropagatorio.opentelemetry:opentelemetry-extension-trace-propagators:1.50.0OpenTracing伝播プロトコルを使用してトレースコンテキストを伝播します。
PassThroughPropagatorio.opentelemetry:opentelemetry-api-incubator:1.50.0-alphaテレメトリーに参加することなく、設定可能なフィールドセットを伝播します。
AwsXrayPropagatorio.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.46.0-alphaAWS X-Ray伝播プロトコルを使用してトレースコンテキストを伝播します。
AwsXrayLambdaPropagatorio.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.46.0-alpha環境変数とAWS X-Ray伝播プロトコルを使用してトレースコンテキストを伝播します。

以下のコードスニペットはTextMapPropagatorのプログラム設定を示します。

package otel;

import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;

public class ContextPropagatorsConfig {
  public static ContextPropagators create() {
    return ContextPropagators.create(
        TextMapPropagator.composite(
            W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()));
  }
}

独自のカスタムプロパゲーターロジックを提供するには、TextMapPropagatorインターフェースを実装してください。 例を挙げましょう。

package otel;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;
import java.util.Collection;
import java.util.Collections;

public class CustomTextMapPropagator implements TextMapPropagator {

  @Override
  public Collection<String> fields() {
    // 伝播に使用されるフィールドを返します。参照実装については W3CTraceContextPropagator を参照してください。
    return Collections.emptyList();
  }

  @Override
  public <C> void inject(Context context, C carrier, TextMapSetter<C> setter) {
    // コンテキストを注入します。参照実装については W3CTraceContextPropagator を参照してください。
  }

  @Override
  public <C> Context extract(Context context, C carrier, TextMapGetter<C> getter) {
    // コンテキストを抽出します。参照実装については W3CTraceContextPropagator を参照してください。
    return context;
  }
}

付録

内部ログ

SDKコンポーネントは、関連するコンポーネントの完全修飾クラス名に基づくロガー名を使用して、さまざまなログレベルでjava.util.loggingにさまざまな情報をログ出力します。

デフォルトでは、ログメッセージはアプリケーションのルートハンドラーによって処理されます。 アプリケーション用にカスタムルートハンドラーをインストールしていない場合、デフォルトでINFOレベル以上のログがコンソールに送信されます。

OpenTelemetryのロガーの動作を変更したい場合があります。 たとえば、デバッグ時に追加情報を出力するためにログレベルを下げたり、特定のクラスからのエラーを無視するために特定のクラスのレベルを上げたり、OpenTelemetryが特定のメッセージをログ出力するたびにカスタムコードを実行するためにカスタムハンドラーまたはフィルターをインストールしたりできます。 ロガー名とログ情報の詳細なリストは維持されていません。 ただし、すべてのOpenTelemetry API、SDK、contrib、および計装コンポーネントは同じio.opentelemetry.*パッケージプレフィックスを共有しています。 すべてのio.opentelemetry.*に対してより細かいログを有効にし、出力を検査し、興味のあるパッケージやFQCNに絞り込むことが有用です。

例を挙げましょう。

## すべてのOpenTelemetryログを無効にする
io.opentelemetry.level = OFF
## BatchSpanProcessorのログのみを無効にする
io.opentelemetry.sdk.trace.export.BatchSpanProcessor.level = OFF
## デバッグに役立つ「FINE」メッセージをログ出力
io.opentelemetry.level = FINE

## デフォルトのConsoleHandlerのロガーのレベルを設定
## これはOpenTelemetry以外のログにも影響することに注意
java.util.logging.ConsoleHandler.level = FINE

より細かい制御と特殊ケースの処理のために、カスタムハンドラーとフィルターをコードで指定できます。

// エクスポートからのエラーをログ出力しないカスタムフィルター
public class IgnoreExportErrorsFilter implements java.util.logging.Filter {

 public boolean isLoggable(LogRecord record) {
    return !record.getMessage().contains("Exception thrown by the export");
 }
}
## BatchSpanProcessorにカスタムフィルターを登録
io.opentelemetry.sdk.trace.export.BatchSpanProcessor = io.opentelemetry.extension.logging.IgnoreExportErrorsFilter

OTLPエクスポーター

スパンエクスポーターメトリクスエクスポーターログエクスポーターセクションでは、以下の形式のOTLPエクスポーターについて説明しています。

  • OtlpHttp{Signal}Exporterは、OTLP http/protobufを介してデータをエクスポートします
  • OtlpGrpc{Signal}Exporterは、OTLP grpcを介してデータをエクスポートします

すべてのシグナルのエクスポーターはio.opentelemetry:opentelemetry-exporter-otlp:1.50.0を介して利用可能で、OTLPプロトコルのgrpchttp/protobufバージョン間、およびシグナル間で大幅に重複しています。 以下のセクションでは、これらの重要な概念について詳しく説明します。

  • センダー:異なるHTTP / gRPCクライアントライブラリの抽象化
  • OTLPエクスポーターの認証オプション

Senders

OTLPエクスポーターは、HTTPおよびgRPCリクエストを実行するためにさまざまなクライアントライブラリに依存しています。 Javaエコシステムのすべての使用例を満たす単一のHTTP / gRPCクライアントライブラリはありません。

  • Java 11+は組み込みのjava.net.http.HttpClientを提供しますが、opentelemetry-javaはJava 8+ユーザーをサポートする必要があり、トレーラーヘッダーのサポートがないためgRPC経由でエクスポートするために使用できません
  • OkHttpはトレーラーヘッダーをサポートする強力なHTTPクライアントを提供しますが、kotlin標準ライブラリに依存しています
  • grpc-javaは、さまざまなトランスポート実装を持つ独自のManagedChannel抽象化を提供しますが、http/protobufには適していません

さまざまな使用例に対応するため、opentelemetry-exporter-otlpは内部の「sender」抽象化を使用し、アプリケーションの制約を反映するさまざまな実装を提供しています。 別の実装を選択するには、デフォルトのio.opentelemetry:opentelemetry-exporter-sender-okhttp依存関係を除外し、代替に依存関係を追加してください。

アーティファクト説明OTLPプロトコルデフォルト
io.opentelemetry:opentelemetry-exporter-sender-okhttp:1.50.0OkHttpベースの実装。grpc, http/protobufはい
io.opentelemetry:opentelemetry-exporter-sender-jdk:1.50.0Java 11+ java.net.http.HttpClientベースの実装。http/protobufいいえ
io.opentelemetry:opentelemetry-exporter-sender-grpc-managed-channel:1.50.0 [1]grpc-java ManagedChannelベースの実装。grpcいいえ

[1]: opentelemetry-exporter-sender-grpc-managed-channelを使用するには、gRPCトランスポート実装への依存関係も追加する必要があります。

認証

OTLPエクスポーターは、静的および動的ヘッダーベース認証、およびmTLSのメカニズムを提供します。

環境変数とシステムプロパティでゼロコードSDK自動設定を使用している場合は、関連するシステムプロパティを参照してください。

  • 静的ヘッダーベース認証にはotel.exporter.otlp.headers
  • mTLS認証にはotel.exporter.otlp.client.keyotel.exporter.otlp.client.certificate

以下のコードスニペットは、静的および動的ヘッダーベース認証のプログラム設定を示します。

package otel;

import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.function.Supplier;

public class OtlpAuthenticationConfig {
  public static void staticAuthenticationHeader(String endpoint) {
    // OTLP宛先がAPIキーのような静的で長期間有効な認証ヘッダーを受け入れる場合、
    // それをヘッダーとして設定します。
    // これは、ソースコードにシークレットをハードコードすることを避けるため、
    // OTLP_API_KEY環境変数からAPIキーを読み取ります。
    String apiKeyHeaderName = "api-key";
    String apiKeyHeaderValue = System.getenv("OTLP_API_KEY");

    // 類似のパターンを使用してOTLP Span、Metric、LogRecordエクスポーターを初期化
    OtlpHttpSpanExporter spanExporter =
        OtlpHttpSpanExporter.builder()
            .setEndpoint(endpoint)
            .addHeader(apiKeyHeaderName, apiKeyHeaderValue)
            .build();
    OtlpHttpMetricExporter metricExporter =
        OtlpHttpMetricExporter.builder()
            .setEndpoint(endpoint)
            .addHeader(apiKeyHeaderName, apiKeyHeaderValue)
            .build();
    OtlpHttpLogRecordExporter logRecordExporter =
        OtlpHttpLogRecordExporter.builder()
            .setEndpoint(endpoint)
            .addHeader(apiKeyHeaderName, apiKeyHeaderValue)
            .build();
  }

  public static void dynamicAuthenticationHeader(String endpoint) {
    // OTLP宛先が定期的に更新が必要なJWTなどの動的認証ヘッダーを要求する場合、
    // ヘッダーサプライヤーを使用します。
    // ここでは「Authorization: Bearer <token>」形式のヘッダーを追加するシンプルなサプライヤーを実装し、
    // <token>は10分ごとにrefreshBearerTokenから取得されます。
    String username = System.getenv("OTLP_USERNAME");
    String password = System.getenv("OTLP_PASSWORD");
    Supplier<Map<String, String>> supplier =
        new AuthHeaderSupplier(() -> refreshToken(username, password), Duration.ofMinutes(10));

    // 類似のパターンを使用してOTLP Span、Metric、LogRecordエクスポーターを初期化
    OtlpHttpSpanExporter spanExporter =
        OtlpHttpSpanExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build();
    OtlpHttpMetricExporter metricExporter =
        OtlpHttpMetricExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build();
    OtlpHttpLogRecordExporter logRecordExporter =
        OtlpHttpLogRecordExporter.builder().setEndpoint(endpoint).setHeaders(supplier).build();
  }

  private static class AuthHeaderSupplier implements Supplier<Map<String, String>> {
    private final Supplier<String> tokenRefresher;
    private final Duration tokenRefreshInterval;
    private Instant refreshedAt = Instant.ofEpochMilli(0);
    private String currentTokenValue;

    private AuthHeaderSupplier(Supplier<String> tokenRefresher, Duration tokenRefreshInterval) {
      this.tokenRefresher = tokenRefresher;
      this.tokenRefreshInterval = tokenRefreshInterval;
    }

    @Override
    public Map<String, String> get() {
      return Collections.singletonMap("Authorization", "Bearer " + getToken());
    }

    private synchronized String getToken() {
      Instant now = Instant.now();
      if (currentTokenValue == null || now.isAfter(refreshedAt.plus(tokenRefreshInterval))) {
        currentTokenValue = tokenRefresher.get();
        refreshedAt = now;
      }
      return currentTokenValue;
    }
  }

  private static String refreshToken(String username, String password) {
    // 本番シナリオでは、これはユーザー名/パスワードをベアラートークンに交換するための
    // アウトオブバンドリクエストに置き換えられます。
    return "abc123";
  }
}

テスト

TODO: SDKのテストに利用可能なツールをドキュメント化