# OpenTracingとの互換性

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/compatibility/opentracing/


**ステータス**: [Deprecated](../../document-status/)

> [!NOTE]
> OpenTracingとの互換性に関する要求事項は非推奨（Deprecated）です。
> 既存のOpenTracingシムは、後方互換性のために継続してサポートされてもかまいません（MAY）が、
> 新たにOpenTracing互換性を実装することは本仕様書によって要求されません。
>
> OpenTracingとの互換性に関する要求事項は、2026年3月時点で非推奨となっています。
> 本仕様書内のOpenTracingとの互換性に関する要求事項は、2027年3月より前には削除されません。

## Abstract

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

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

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

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

[Set Tag](#set-tag)と[Log](#log)の節で説明されているエラーのマッピングを除き、セマンティック規約のマッピングは行うべきではありません（SHOULD NOT）。

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

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

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

## Language version support

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

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

[Language version support]: https://opentelemetry.io/docs/compatibility/migration/opentracing/#language-version-support
[Migrating from OpenTracing]: https://opentelemetry.io/docs/compatibility/migration/opentracing/

## Create an OpenTracing Tracer Shim

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

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

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

APIはOpenTracingの`Tracer`を返さなければなりません（MUST）。

```java
// 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の伝搬[形式](https://github.com/opentracing/specification/blob/master/specification.md#extract-a-spancontext-from-a-carrier)を参照してください。

## Tracer Shim

### Start a new Span

パラメータ:

- 操作名。文字列。
- [Spanの参照](#span-references)の任意のリスト。
- [タグ](#set-tag)の任意のリスト。
- 明示的な開始タイムスタンプ。数値。任意。

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

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

`Span`参照のリストが指定されている場合、リスト全体の中で**Child Of**種別を持つ最初の`SpanContext`が親として使われ、そうでなければ最初の`SpanContext`が親として使われます。リスト内のすべての値は、参照種別の値を`Link`の属性として（すなわち[opentracing.ref_type](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/trace-compatibility.md#opentracing)を`follows_from`または`child_of`に設定した上で）[Link](/works/otel-specs-ja/spec/trace/api/)として追加されなければなりません（MUST）。

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

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

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

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

APIはOpenTracingの`Span`を返さなければなりません（MUST）。

### Inject

パラメータ:

- `SpanContext`。
- `Format`記述子。
- キャリア。

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

- `TextMap`と`HttpHeaders`の形式は、明示的に指定された`TextMapPropagator`があればそれを使い、なければグローバルな`TextMapPropagator`を使わなければなりません（MUST）。

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

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

### Extract

パラメータ:

- `Format`記述子。
- キャリア。

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

- `TextMap`と`HttpHeaders`の形式は、明示的に指定された`TextMapPropagator`があればそれを使い、なければグローバルな`TextMapPropagator`を使わなければなりません（MUST）。

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

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

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

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

return SpanContextShim(extractedSpanContext, extractedBaggage);
```

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

注: 無効だがサンプリングされている`SpanContext`インスタンスが返されるのは、デバッグ情報の伝搬を強制するために使われる`jaeger-debug-id`[ヘッダー](https://github.com/jaegertracing/jaeger-client-java#via-http-headers)をサポートする手段としてです。

## 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`が正しく伝搬されない場合があります。

```java
// 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の`Span`と`Baggage`の値を使って実装されなければなりません（MUST）。

`Log`操作は、OpenTelemetryの`Span`の`Add Events`操作を使って実装されなければなりません（MUST）。

`Set Tag`操作は、OpenTelemetryの`Span`の`Set Attributes`操作を使って実装されなければなりません（MUST）。

### Get Context

現在の`SpanContext` Shimを返します。

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

### Get Baggage Item

パラメータ:

- baggageのキー。文字列。

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

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

```java
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）。

```java
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の`Span`の`Set Attribute`を呼び出します。

`error`タグは、[StatusCode](/works/otel-specs-ja/spec/trace/api/#set-status)へ[マッピング](https://github.com/opentracing/specification/blob/master/semantic_conventions.md#standard-span-tags-and-log-fields)されなければなりません（MUST）。

- `true`は`Error`にマッピングされます。
- `false`は`Ok`にマッピングされます。
- 値が設定されない場合は`Unset`にマッピングされます。

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

### Log

パラメータ:

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

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

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

ペアの集合に`event=error`のエントリが含まれる場合、それらの値は、[Exception semantic conventions](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/exceptions/exceptions-spans.md)文書に示された規約に従って`Event`へ[マッピング](https://github.com/opentracing/specification/blob/master/semantic_conventions.md#log-fields-table)されなければなりません（MUST）。

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

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

### Finish

基盤となるOpenTelemetryの`Span`の`End`を呼び出します。

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

## SpanContext Shim

`SpanContext` Shimはイミュータブルでなければならず（MUST）、関連付けられた`SpanContext`と`Baggage`の値を含まなければなりません（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](/works/otel-specs-ja/spec/trace/api/#spancontextのspanへのラッピング)に設定されなければなりません（MUST）。

```java
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`を持つため、問題なくアクティベートできます。

```java
// 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の`Span`の`SpanContext`が無効であり、かつ現在の`Baggage`が空である場合、アクティブな`Span`もBaggageも存在しないことを示すため、この操作は直ちにnullを返さなければなりません（MUST）。

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

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

```java
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の仕様](https://github.com/opentracing/specification/blob/master/specification.md#references-between-spans)で定義されているように、`Span`は因果関係を持つゼロ個以上の他の`SpanContext`を参照できます。参照情報自体は、`SpanContext`と参照種別から構成されます。

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

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

OpenTelemetryは、これらの参照に厳密に相当するセマンティクスを定義していません。これらの参照種別は、[Link](/works/otel-specs-ja/spec/trace/api/#link)機能と混同してはなりません。ただし、この情報は`opentracing.ref_type`属性として保持されます。

## In process Propagation exceptions

### Implicit and Explicit support mismatch

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

```ts
// 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）ものとします。

```ts
// 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;
    }
    ...
  }
  ...
}
```

