OpenTracingとの互換性

この記事は英語の原文を日本語に翻訳したものです。原文: https://opentelemetry.io/docs/specs/otel/compatibility/opentracing/

翻訳元: open-telemetry/opentelemetry-specification v1.60.0(コミット 29ae8c7

ステータス: Deprecated

[!NOTE] OpenTracingとの互換性に関する要求事項は非推奨(Deprecated)です。 既存のOpenTracingシムは、後方互換性のために継続してサポートされてもかまいません(MAY)が、 新たにOpenTracing互換性を実装することは本仕様書によって要求されません。

OpenTracingとの互換性に関する要求事項は、2026年3月時点で非推奨となっています。 本仕様書内のOpenTracingとの互換性に関する要求事項は、2027年3月より前には削除されません。

Abstract

OpenTelemetryプロジェクトは、計装済みのコードベースの移行を容易にするため、OpenTracingプロジェクトとの後方互換性の提供を目指しています。

この機能は、OpenTelemetry APIを使ってOpenTracing APIを実装するブリッジ層として提供されます。この層は、いずれのSDKの実装固有の詳細にも依存してはなりません(MUST NOT)。

より具体的には、OpenTracingの計装をOpenTelemetryを使って記録できるようにすることが意図されています。このシム層は、upstreamのOpenTelemetry APIを公に公開してはなりません(MUST NOT)。

歴史的に、この機能はOpenTracingにもOpenTelemetryのAPIやSDKにも属さない、独自のOpenTracingシム層として定義されていました。この互換性は非推奨であるため、新しい実装は必要とされません。

Set TagLogの節で説明されているエラーのマッピングを除き、セマンティック規約のマッピングは行うべきではありません(SHOULD NOT)。

同じコードベースでOpenTracingシムとOpenTelemetry APIの両方を利用することは、以下のシナリオでは推奨されません。

  • OpenTracingで計装されたコードがbaggageを利用する場合。Baggage自体が正しく伝搬されない可能性があります。 Span ShimとSpanContext Shimの関係を参照してください。
  • OpenTelemetryではプロセス内伝搬が暗黙的にサポートされているが、OpenTracingではサポートされていない言語(例えばJavaScript)の場合。想定されている伝搬のセマンティクスが崩れ、Contextの誤った使用や不正なトレースにつながる可能性があります。 暗黙的サポートと明示的サポートの不一致を参照してください。

このセクションは、移行と後方互換性のガイダンスのために残されています。

Language version support

シム層を使う前に、利用者は自身の言語やランタイムのコンポーネントを確認し、更新することが推奨されます。OpenTelemetryのAPIとSDKは、対応するOpenTracingのものより高いバージョンを要求する場合があるためです。

詳細は、OpenTracingからの移行Language version supportの節を参照してください。

Create an OpenTracing Tracer Shim

この操作は、新しいOpenTracingのTracerを作成するために使われます。

この操作は、以下のパラメータを受け入れなければなりません(MUST)。

  • OpenTelemetryのTracerProvider。この操作は、このTracerProviderを使って、名前opentracing-shimと現在のシムライブラリのバージョンを持つTracerを取得しなければなりません(MUST)。
  • OpenTracingのTextMapおよびHTTPHeaders形式に対して注入・抽出を行うために使われる、OpenTelemetryのPropagator群。指定されない場合、シムにはPropagatorの値は一切保存されず、OpenTracingのTextMapHTTPHeadersの両方の形式に対して、グローバルなOpenTelemetryのTextMapプロパゲーターが使われます。

APIはOpenTracingのTracerを返さなければなりません(MUST)。

// Create a Tracer Shim relying on the global propagators.
createTracerShim(tracerProvider);

// Create a Tracer Shim using:
// 1) TraceContext propagator for TextMap
// 2) Jaeger propagator for HttPHeaders.
createTracerShim(tracerProvider, OTPropagatorsBuilder()
  .setTextMap(W3CTraceContextPropagator.getInstance())
  .setHttpHeaders(JaegerPropagator.getInstance())
  .build());

OpenTracingの伝搬形式を参照してください。

Tracer Shim

Start a new Span

パラメータ:

  • 操作名。文字列。
  • Spanの参照の任意のリスト。
  • タグの任意のリスト。
  • 明示的な開始タイムスタンプ。数値。任意。

ScopeManagerインターフェースを実装しているOpenTracingの言語では、以下のパラメータも定義されます。

  • 現在のSpanを自動的な親として無視すべきかどうかを指定する、任意のブール値。

Span参照のリストが指定されている場合、リスト全体の中でChild Of種別を持つ最初のSpanContextが親として使われ、そうでなければ最初のSpanContextが親として使われます。リスト内のすべての値は、参照種別の値をLinkの属性として(すなわちopentracing.ref_typefollows_fromまたはchild_ofに設定した上で)Linkとして追加されなければなりません(MUST)。

Span参照のリストが指定されている場合、それらのBaggage値の和集合が、新しく作成されるSpanの初期Baggageとして使われなければなりません(MUST)。キーが重複する場合にどちらのBaggage値が使われるかは規定されていません。そのような参照のリストが指定されない場合、現在のBaggageが新しく作成されるSpanの初期値として使われなければなりません(MUST)。

初期のタグの集合が指定されている場合、それらの値は、Spanが既に作成された後に設定するのではなく、OpenTelemetryのSpanの作成時に設定されなければなりません(MUST)。これは、初期のタグ・属性を含むSpanの情報を参照するSpan作成前のフックにその値を利用可能にするために行われます。例えば、参照SDKは、サンプリングするかどうかを判断するためにSpanの情報を参照するサンプリングのステップを実行します。

初期のタグの集合が指定され、OpenTracingのerrorタグが含まれている場合、OpenTelemetryのSpanが作成された後、シム層はSet Tag操作で説明されているのと同じエラー処理を行わなければなりません(MUST)。

明示的な開始タイムスタンプが指定されている場合、OpenTracingとOpenTelemetryの単位を一致させる変換を行わなければなりません(MUST)。

APIはOpenTracingのSpanを返さなければなりません(MUST)。

Inject

パラメータ:

  • SpanContext
  • Format記述子。
  • キャリア。

構築時に設定された、明示的に登録されたOpenTelemetryのPropagator、またはグローバルなOpenTelemetryのPropagatorのいずれかを使って、基盤となるOpenTelemetryのSpanBaggageを注入します。

  • TextMapHttpHeadersの形式は、明示的に指定されたTextMapPropagatorがあればそれを使い、なければグローバルなTextMapPropagatorを使わなければなりません(MUST)。

有効なSpanContextが存在しない場合でも、空でないBaggageは注入しなければなりません(MUST)。

指定されたFormatが認識されない場合、具体的なOpenTracing言語のAPI次第で、エラーが発生してもかまいません(MAY)(例えばGoやPythonでは発生しますが、Javaでは発生しない場合があります)。

Extract

パラメータ:

  • Format記述子。
  • キャリア。

構築時に設定された、明示的に登録されたOpenTelemetryのPropagator、またはグローバルなOpenTelemetryのPropagatorのいずれかを使って、基盤となるOpenTelemetryのSpanBaggageを抽出します。

  • TextMapHttpHeadersの形式は、明示的に指定されたTextMapPropagatorがあればそれを使い、なければグローバルなTextMapPropagatorを使わなければなりません(MUST)。

以下のいずれかの条件が満たされる場合、この操作は抽出された値を持つSpanContext Shimインスタンスを返さなければなりません(MUST)。

  • SpanContextが有効である。
  • SpanContextがサンプリングされている。
  • SpanContextが空でない抽出済みのBaggageを含む。

そうでない場合、この操作はnullまたは空の値を返さなければなりません(MUST)。

if (!extractedSpanContext.isValid()
    && !extractedSpanContext.isSampled()
    && extractedBaggage.isEmpty()) {
  return null;
}

return SpanContextShim(extractedSpanContext, extractedBaggage);

Formatが認識されない場合、または値を何も抽出できなかった場合、具体的なOpenTracing言語のAPI次第で、エラーが発生してもかまいません(MAY)(例えばGoやPythonでは発生しますが、Javaでは発生しない場合があります)。

注: 無効だがサンプリングされているSpanContextインスタンスが返されるのは、デバッグ情報の伝搬を強制するために使われるjaeger-debug-idヘッダーをサポートする手段としてです。

Close

任意(OPTIONAL)の操作です。この操作が特定のOpenTracing言語向けに実装される場合、基盤となるTracerProviderが「closeable」なインターフェースやメソッドを実装していればそれをクローズしなければならず(MUST)、そうでなければno-opの操作として定義されなければなりません(MUST)。

シム層は、基盤となるTracerProviderをクローズする際に発生するエラーや例外から保護しなければなりません(MUST)。

注: TracerProviderごとにこの操作を複数回呼び出すことは推奨されません。予期しない副作用、制約、または競合状態(単一のShim Tracerが複数回クローズされる、あるいは複数のShim Tracerのクローズ操作が呼び出される、など)を引き起こす可能性があるためです。

Span Shim and SpanContext Shim relationship

OpenTracingの仕様に従い、OpenTracingのSpanContext ShimはBaggageデータを含まなければならず(MUST)、イミュータブルでなければなりません(MUST)。

さらに、OpenTracingのSpan ShimはSpanContext Shimを含まなければなりません(MUST)。関連付けられたbaggageを更新する際、OpenTracingのSpanは、更新後のBaggageを含む新しいインスタンスをOpenTracingのSpanContext Shimとして設定しなければなりません(MUST)。

これは、上述したオブジェクトの簡単な図式表現です。

  Span Shim
  +- OpenTelemetry Span (read-only)
  +- SpanContext Shim
        +- OpenTelemetry SpanContext (read-only)
        +- OpenTelemetry Baggage (read-only)

OpenTracingシムは、上記のオブジェクトの階層を利用して、OpenTelemetryのSpanとそれに関連付けられたBaggageについて、プロセス内・プロセス間の伝搬を適切に行います。

OpenTelemetryはこの関連付けを認識していないため、以下の例のように、同じコードベースでOpenTracingシムとOpenTelemetry APIの両方が利用されると、関連するBaggageが正しく伝搬されない場合があります。

// methodOne consumes the OpenTelemetry API.
void methodOne(Span span) {
  try (Scope scope = span.makeCurrent()) {
    methodTwo();
  }
}

// methodTwo consumes the OpenTracing Shim.
void methodTwo() {
  io.opentracing.Span span = io.opentracing.util.GlobalTracer.get()
    .activeSpan();

  // Correctly set in the underlying io.opentelemetry.api.trace.Span
  span.setTag("tag", "value");

  // Value is set in the Shim layer -- it may not be later propagated
  // as OpenTelemetry is not aware of the Baggage associated
  // to this Span.
  span.setBaggageItem("baggage", "item");
}

関連付けられたBaggageにアクセスする操作は、並行して呼び出されても安全でなければなりません(MUST)。

Span Shim

OpenTracingのSpanの操作は、SpanContext Shimオブジェクトの助けを借りて、基盤となるOpenTelemetryのSpanBaggageの値を使って実装されなければなりません(MUST)。

Log操作は、OpenTelemetryのSpanAdd Events操作を使って実装されなければなりません(MUST)。

Set Tag操作は、OpenTelemetryのSpanSet Attributes操作を使って実装されなければなりません(MUST)。

Get Context

現在のSpanContext Shimを返します。

この操作は、並行して呼び出されても安全でなければなりません(MUST)。

Get Baggage Item

パラメータ:

  • baggageのキー。文字列。

現在のSpanContext ShimのOpenTelemetry Baggage内で指定されたキーに対応する値を返し、存在しない場合はnullを返します。

この操作は、並行して呼び出されても安全でなければなりません(MUST)。

String getBaggageItem(String key) {
  synchronized(this) {
    // Get the current SpanContext's Baggage.
    io.opentelemetry.baggage.Baggage baggage = this.spanContextShim.getBaggage();

    // Return the value for key.
    return baggage.getEntryValue(key);
  }
}

Set Baggage Item

パラメータ:

  • baggageのキー。文字列。
  • baggageの値。文字列。

指定されたBaggageのキーと値のペアを含む新しいOpenTelemetryのBaggageを持つ新しいSpanContext Shimを作成し、それをこのSpan Shimの現在のインスタンスとして設定します。

この操作は、並行して呼び出されても安全でなければなりません(MUST)。

void setBaggageItem(String key, String value) {
  synchronized(this) {
    // Add value/key to the existing Baggage.
    Baggage newBaggage = this.spanContextShim.getBaggage().toBuilder()
      .put(key, value)
      .build();

    // Create a new SpanContext with the updated Baggage.
    SpanContextShim newSpanContextShim = this.spanContextShim
      .newWithBaggage(newBaggage);

    // Update our SpanContext instance.
    this.spanContextShim = newSpanContextShim;
  }
}

Set Tag

パラメータ:

  • タグのキー。文字列。
  • タグの値。文字列、ブール値、数値型のいずれかでなければなりません。

指定されたキーと値のペアを使って、基盤となるOpenTelemetryのSpanSet Attributeを呼び出します。

errorタグは、StatusCodeマッピングされなければなりません(MUST)。

  • trueErrorにマッピングされます。
  • falseOkにマッピングされます。
  • 値が設定されない場合はUnsetにマッピングされます。

指定された値の型がOTel APIでサポートされていない場合、その値は文字列に変換されなければなりません(MUST)。

Log

パラメータ:

  • キーと値のペアの集合。キーは文字列でなければならず、値は任意の型を取り得ます。

指定されたキーと値のペアの集合を使って、基盤となるOpenTelemetryのSpanAdd Eventsを呼び出します。

Add Eventnameパラメータは、ペアの集合内のeventキーの値でなければならず(MUST)、それがなければ文字列リテラルlogにフォールバックします。

ペアの集合にevent=errorのエントリが含まれる場合、それらの値は、Exception semantic conventions文書に示された規約に従ってEventマッピングされなければなりません(MUST)。

  • error.objectキーを持つエントリが存在し、その値が言語固有のエラーオブジェクトである場合、指定されたキーと値のペアの残りを追加のイベント属性として、RecordException(e)の呼び出しが行われます。
  • そうでない場合、nameexceptionに設定した上で、指定されたキーと値のペアの集合を追加のイベント属性として(以下のキーと値のペアのマッピングを含めて)、AddEventの呼び出しが行われます。
    • error.kindexception.typeにマッピングされます。
    • messageexception.messageにマッピングされます。
    • stackexception.stacktraceにマッピングされます。

明示的なタイムスタンプが指定されている場合、OpenTracingとOpenTelemetryの単位を一致させる変換を行わなければなりません(MUST)。

Finish

基盤となるOpenTelemetryのSpanEndを呼び出します。

明示的なタイムスタンプが指定されている場合、OpenTracingとOpenTelemetryの単位を一致させる変換を行わなければなりません(MUST)。

SpanContext Shim

SpanContext Shimはイミュータブルでなければならず(MUST)、関連付けられたSpanContextBaggageの値を含まなければなりません(MUST)。

Get Baggage Items

(特定言語のOpenTracing APIの要求事項に応じて)関連付けられたOpenTelemetryのBaggageの値を裏付けとする、辞書、コレクション、またはイテレーターを返します。

ScopeManager Shim

ScopeManagerインターフェースを実装しているOpenTracingの言語では、その操作は、現在アクティブなContextインスタンスを取得・設定するために、OpenTelemetryのContext Propagation APIを使って実装されなければなりません(MUST)。

Activate a Span

パラメータ:

  • Span

Span Shimと、その基盤となるSpanおよびBaggageを新しいContextに格納し、それを現在アクティブなインスタンスとして設定します。

指定されたSpanがnullの場合、アクティブなSpanもBaggageも存在しないことを示すために、無効なSpanContextをラップするNonRecordableSpanに設定されなければなりません(MUST)。

Scope activate(Span span) {
  if (span == null) {
    span = new SpanShim(io.opentelemetry.api.trace.Span.getInvalid());
  }

  SpanShim spanShim = (SpanShim)span;

  // Put the associated Span and Baggage in a new Context.
  Context context = Context.current()
    .withValue(spanShim)
    .withValue(spanShim.getSpan())
    .withValue(spanShim.getBaggage());

  // Set context as the current instance.
  return context.makeCurrent();
}

サンプリングされていないOpenTelemetryのSpanも、(sampledフラグがfalseに設定されているとはいえ)有効なSpanContextを持つため、問題なくアクティベートできます。

// The underlying OpenTelemetry TracerProvider's Sampler
// decided to NOT sample this Span, hence
// io.opentelemetry.api.trace.Span.getSpanContext().isSampled() == false.
Span span = tracer.buildSpan("operationName").start();

try (Scope scope = tracer.scopeManager().activate(span)) {
  // tracer.scopeManager().activeSpan() == span
}

Get the active Span

現在アクティブなOpenTelemetryのSpanをラップするSpan Shimを返します。

現在のOpenTelemetryのSpanSpanContextが無効であり、かつ現在のBaggageが空である場合、アクティブなSpanもBaggageも存在しないことを示すため、この操作は直ちにnullを返さなければなりません(MUST)。

現在のOpenTelemetryのSpanSpanContextが無効だが、現在のBaggageが空でない場合、この操作は、no-opのOpenTelemetryのSpanと空でないBaggageを含む新しいSpan Shimを返さなければなりません(MUST)。

現在のContext内に一致するOpenTelemetryのSpanSpan Shimオブジェクトが存在する場合、そのSpan Shimが返されなければなりません(MUST)。そうでない場合、現在のOpenTelemetryのSpanBaggageを含む新しいSpan Shimが返されなければなりません(MUST)。

Span active() {
  io.opentelemetry.api.trace.Span span = Span.fromContext(Context.current());
  io.opentelemetry.api.baggage.Baggage baggage = Baggage.fromContext(Context.current());
  SpanShim spanShim = SpanShim.fromContext(Context.current());

  // There is no actual currently active Span.
  if (!span.getSpanContext().isValid()) {
    // Immediately return null if there is no Baggage.
    if (baggage.isEmpty()) {
      return null;
    }

    // Else return a no-op Span with the Baggage.
    return SpanShim(baggage);
  }

  // Span was activated through the Shim layer, re-use it.
  if (spanShim != null && spanShim.getSpan() == span) {
    return spanShim;
  }

  // Span was NOT activated through the Shim layer,
  // do a best effort with the current values.
  new SpanShim(span, baggage);
}

Span References

OpenTracingの仕様で定義されているように、Spanは因果関係を持つゼロ個以上の他のSpanContextを参照できます。参照情報自体は、SpanContextと参照種別から構成されます。

OpenTracingは2種類の参照を定義しています。

  • Child Of: 親Spanは、何らかの点で子Spanに依存します。
  • Follows From: 親Spanは、その子Spanの結果にまったく依存しません。

OpenTelemetryは、これらの参照に厳密に相当するセマンティクスを定義していません。これらの参照種別は、Link機能と混同してはなりません。ただし、この情報はopentracing.ref_type属性として保持されます。

In process Propagation exceptions

Implicit and Explicit support mismatch

OpenTelemetryではプロセス内伝搬が暗黙的にサポートされているが、OpenTracingではサポートされていない(すなわちScopeManagerのサポートがない)言語の場合、シムはその操作(例えば新しいSpanを開始するときなど)において明示的なコンテキスト伝搬のみを使わなければなりません(MUST)。これは、OpenTracing APIの明示的伝搬のみというセマンティクスに簡単に準拠するために行われます。

// Tracer Shim
startSpan(name: string, options: SpanOptions = {}): Span {
  const otelSpanOptions = ...;

  if (!options.childOf && !options.references) {
    // Do NOT get nor set the current Context/Span,
    // as it is part of the implicit propagation support.
    otelSpanOptions.root = true;
  }
  ...
}

同じコードベースでOpenTracingシムとOpenTelemetry APIの両方を使うと、暗黙的/明示的な伝搬に関する想定の違いにより、トレースが誤った親Spanを使ってしまう場合があります。この場合、シムは、誤った親の値が使われる可能性があることを利用者に警告しつつ、明示的な設定を通じてOpenTelemetryの暗黙的なプロセス内伝搬との**開発中(in-Development)**の統合を提供してもよい(MAY)ものとします。

// Tracer Shim
startSpan(name: string, options: SpanOptions = {}): Span {
  const otelSpanOptions = ...;

  if (!options.childOf && !options.references) {
    if (otShimOptions.supportImplicitPropagation) {
      // Allow OpenTelemetry to consume the current Context
      // to fetch the parent Span.
      otelSpanOptions.root = false;
    }
    ...
  }
  ...
}