# トレーシングAPI

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/trace/api/


**ステータス**: 特記のない限り[Stable](../../document-status/)

トレーシングAPIは、以下の主要なコンポーネントから構成されます。

- [`TracerProvider`](#tracerprovider)はAPIのエントリーポイントです。`Tracer`へのアクセスを提供します。
- [`Tracer`](#tracer)は`Span`の作成を担います。
- [`Span`](#span)は、1つの操作をトレースするためのAPIです。

## データ型

言語やプラットフォームによってデータの表現方法は異なりますが、本節ではこのAPIに関する汎用的な要件をいくつか定義します。

### 時刻

OpenTelemetryは、最大でナノ秒（ns）精度までの時刻値を扱えます。これらの値の表現方法は言語に固有です。

#### タイムスタンプ

タイムスタンプとは、UNIXエポックからの経過時間です。

* 最小精度はミリ秒です。
* 最大精度はナノ秒です。

#### 期間

期間とは、2つのイベント間の経過時間です。

* 最小精度はミリ秒です。
* 最大精度はナノ秒です。

## TracerProvider

`Tracer`は`TracerProvider`を使って取得できます。

このAPIの実装において、`TracerProvider`は何らかの設定を保持するステートフルなオブジェクトであることが期待されます。

通常、`TracerProvider`は中央の一箇所からアクセスされることが期待されます。したがって、APIはグローバルなデフォルトの`TracerProvider`を設定・登録およびアクセスする方法をSHOULD提供するものとします。

いかなるグローバルな`TracerProvider`があるかにかかわらず、一部のアプリケーションは複数の`TracerProvider`インスタンスを使いたい、あるいは使わざるを得ない場合があります。例えば`TracerProvider`インスタンス（そしてそれに応じて、そこから取得される`Tracer`）ごとに異なる設定（`SpanProcessor`など）を持ちたい場合や、依存性注入フレームワークを使う際に簡単だからという理由があります。したがって、`TracerProvider`の実装は、任意の数の`TracerProvider`インスタンスの作成をSHOULD許容するものとします。

### TracerProviderの操作

`TracerProvider`は以下の関数をMUST提供するものとします。

- `Tracer`の取得

#### Tracerの取得

このAPIは以下のパラメータをMUST受け付けるものとします。

- `name`（必須）: この名前は、[Instrumentation Scope](/works/otel-specs-ja/spec/common/instrumentation-scope/)、例えば[Instrumentation Library](../../glossary/#instrumentation-library)（`io.opentelemetry.contrib.mongodb`など）、パッケージ、モジュール、クラス名を一意に識別すべきです（SHOULD）。アプリケーションやライブラリに組み込みのOpenTelemetry計装がある場合、[Instrumented library](../../glossary/#instrumented-library)と[Instrumentation library](../../glossary/#instrumentation-library)は同じライブラリを指すことがあります。このシナリオでは、`name`はそのライブラリまたはアプリケーション内のモジュール名やコンポーネント名を表します。無効な名前（nullまたは空文字列）が指定された場合、nullを返したり例外をスローしたりするのではなく、フォールバックとして動作するTracer実装をMUST返すものとし、その`name`プロパティは**空**の文字列に設定すべきであり（SHOULD）、指定された値が無効であることを報告するメッセージをログに記録すべきです（SHOULD）。OpenTelemetry APIを実装するライブラリは、「名前付き」機能をサポートしない場合（例えばオブザーバビリティに関連しない実装の場合）、この名前を無視してすべての呼び出しに対してデフォルトのインスタンスを返して*も構いません*。アプリケーション所有者がこのライブラリによって生成されるテレメトリーを抑制するようSDKを設定している場合、TracerProviderはここでno-opのTracerを返すこともあります。
- `version`（任意）: そのスコープにバージョンがある場合（例えばライブラリのバージョン）、Instrumentation Scopeのバージョンを指定します。値の例: `1.0.0`。
- [1.4.0以降] `schema_url`（任意）: 発行されるテレメトリーに記録すべきSchema URLを指定します。
- [1.13.0以降] `attributes`（任意）: 発行されるテレメトリーに関連付けるInstrumentation Scopeの属性を指定します。

*identical*（同一）という用語をTracerに適用した場合、すべてのパラメータが等しいインスタンスを表します。*distinct*（別個）という用語をTracerに適用した場合、少なくとも1つのパラメータの値が異なるインスタンスを表します。

実装は、設定変更を反映させるために、ユーザーに同一のIDで`Tracer`を再度取得することをMUST NOT要求するものとします。これは、古い設定での動作を許容するか、新しい設定が以前に返された`Tracer`にも適用されるようにすることで実現できます。

注: これは例えば、可変な設定を`TracerProvider`に保存し、`Tracer`実装オブジェクトが取得元の`TracerProvider`への参照を持つことで実装できます。設定を（特定のtracerを無効化する場合のように）tracerごとに保存する必要がある場合、tracerは自身のIDで`TracerProvider`内のマップを検索できます。あるいは、`TracerProvider`がすべての返却済み`Tracer`のレジストリを保持し、設定が変わった際にそれらの設定を能動的に更新することもできます。

## コンテキストとの相互作用

本節は、[`Context`](/works/otel-specs-ja/spec/context/)と相互作用するトレーシングAPI内のすべての操作を定義します。

このAPIは、`Context`インスタンスと相互作用するために以下の機能をMUST提供するものとします。

- `Context`インスタンスから`Span`を取り出す
- `Span`を`Context`インスタンスと組み合わせ、新しい`Context`インスタンスを作成する

上記の機能が必要な理由は、APIの利用者が、トレーシングAPIの実装が使う[Context Key](/works/otel-specs-ja/spec/context/#create-a-key)へアクセスすべきではない（SHOULD NOT）ためです。

言語が暗黙的に伝搬される`Context`をサポートする場合（[こちら](/works/otel-specs-ja/spec/context/#optional-global-operations)を参照）、APIは以下の機能もSHOULD提供するものとします。

- 暗黙のコンテキストから現在アクティブなspanを取得する。これは、暗黙のコンテキストを取得し、そこから`Span`を取り出すことと同等です。
- 現在アクティブなspanを新しいコンテキストへ設定し、それを暗黙のコンテキストとする。これは、現在の暗黙のコンテキストの値を`Span`と組み合わせて新しいコンテキストを作成し、それを現在の暗黙のコンテキストとすることと同等です。

上記のすべての機能はコンテキストAPIのみを操作するものであり、traceモジュール上の静的メソッド、あるいはtraceモジュール内のクラスの静的メソッドとして公開してもかまいません（MAY）。この機能は、可能であればAPI内で完全に実装されるべきです（SHOULD）。

## Tracer

tracerは`Span`の作成を担います。

`Tracer`は通常、設定の責務を負う*べきではない*ことに注意してください。これは代わりに`TracerProvider`の責務であるべきです。

### Tracerの操作

`Tracer`は以下を行う関数をMUST提供するものとします。

- [新しい`Span`の作成](#span作成)（`Span`に関する節を参照）

`Tracer`は以下を行う関数をSHOULD提供するものとします。

- [`Tracer`が`Enabled`かどうかの報告](#enabled)

#### Enabled

ユーザーが`Span`を作成する際に計算コストの高い操作を行うことを避けられるようにするため、`Tracer`はこの`Enabled` APIをSHOULD提供するものとします。

このAPIには現在必須のパラメータはありません。将来パラメータが追加される可能性があるため、APIはパラメータを追加できる形でMUST構造化されるものとします。

このAPIは言語にとってイディオマティックなブール型をMUST返すものとします。返り値が`true`の場合、指定された引数に対して`Tracer`が有効であることを意味し、`false`の場合は指定された引数に対して`Tracer`が無効であることを意味します。

返される値は常に静的ではなく、時間とともに変化することがあります。このAPIは、計装作者が最新の応答を得るために[新しい`Span`を作成する](#span作成)たびにこのAPIを呼び出す必要があるとドキュメント化されるべきです（SHOULD）。

## SpanContext

`SpanContext`は、分散コンテキストと一緒にシリアライズし伝搬しなければならない`Span`の部分を表します。`SpanContext`はイミュータブルです。

OpenTelemetryの`SpanContext`表現は、[W3C TraceContext仕様](https://www.w3.org/TR/trace-context/)に準拠しています。これには2つの識別子（`TraceId`と`SpanId`）、共通の`TraceFlags`、そしてシステム固有の`TraceState`の値の集合が含まれます。

`TraceId` 有効なトレース識別子は、少なくとも1つの非ゼロバイトを含む16バイトの配列です。

`SpanId` 有効なスパン識別子は、少なくとも1つの非ゼロバイトを含む8バイトの配列です。

`TraceFlags`はトレースに関する詳細を含みます。TraceStateの値とは異なり、TraceFlagsはすべてのトレースに存在します。この仕様書の現バージョンは2つのフラグをサポートします。

- [Sampled](https://www.w3.org/TR/trace-context-2/#sampled-flag)
- [Random](https://www.w3.org/TR/trace-context-2/#random-trace-id-flag)

`TraceState`は、トレーシングシステム固有のトレース識別データをキーと値のペアのリストとして運びます。TraceStateにより、複数のトレーシングシステムが同一トレースに参加できます。これは[W3C Trace Context仕様](https://www.w3.org/TR/trace-context-2/#tracestate-header)で完全に記述されています。`TraceState`におけるOpenTelemetry固有の値については、[TraceState Handling](/works/otel-specs-ja/spec/trace/tracestate-handling/)ドキュメントを参照してください。

`IsRemote`は、SpanContextが他所から受信されたものか、ローカルで生成されたものかを示すブール値です。[IsRemote](#isremote)を参照してください。

APIは`SpanContext`を作成するメソッドをMUST実装するものとします。これらのメソッドは`SpanContext`を作成する唯一の方法であるべきです（SHOULD）。この機能はAPI内でMUST完全に実装されるものとし、オーバーライド可能であるべきではありません（SHOULD NOT）。

### TraceIdとSpanIdの取得

APIは、以下の形式で`TraceId`と`SpanId`の取得をMUST許容するものとします。

* Hex - 小文字の[16進エンコードされた](https://datatracker.ietf.org/doc/html/rfc4648#section-8)`TraceId`（結果は32文字の小文字16進文字列でなければなりません）または`SpanId`（結果は16文字の小文字16進文字列でなければなりません）を返します。
* Binary - `TraceId`（結果は16バイトの配列でなければなりません）または`SpanId`（結果は8バイトの配列でなければなりません）のバイナリ表現を返します。

APIは、それらが内部でどのように保存されているかについての詳細を公開すべきではありません（SHOULD NOT）。

### IsValid

SpanContextが非ゼロのTraceIDと非ゼロのSpanIDを持つ場合に`true`を返すブール値を返す、`IsValid`と呼ばれるAPIがMUST提供されるものとします。

### IsRemote

SpanContextがリモートの親から伝搬されたものである場合に`true`を返すブール値を返す、`IsRemote`と呼ばれるAPIがMUST提供されるものとします。[Propagators API](/works/otel-specs-ja/spec/context/api-propagators/)を通じて`SpanContext`を抽出する際、`IsRemote`はMUST trueを返すものとし、一方で子スパンのSpanContextについてはfalseをMUST返すものとします。

### TraceState

`TraceState`は[`SpanContext`](#spancontext)の一部であり、文字列のキーと値のペアのイミュータブルなリストとして表現され、[W3C Trace Context仕様](https://www.w3.org/TR/trace-context/#tracestate-header)によって正式に定義されています。トレーシングAPIは`TraceState`に対して、少なくとも以下の操作をMUST提供するものとします。

* 指定されたキーの値を取得する
* 新しいキーと値のペアを追加する
* 指定されたキーの既存の値を更新する
* キーと値のペアを削除する

これらの操作は、[W3C Trace Context仕様](https://www.w3.org/TR/trace-context/#mutating-the-tracestate-field)に記述されたルールにMUST従うものとします。すべての変更操作は、変更を適用した新しい`TraceState`をMUST返すものとします。`TraceState`は、常に[W3C Trace Context仕様](https://www.w3.org/TR/trace-context/#tracestate-header-field-values)で指定されたルールに従って有効でなければなりません（MUST）。すべての変更操作は、入力パラメータをMUST検証するものとします。無効な値が渡された場合、その操作は無効なデータを含む`TraceState`をMUST NOT返すものとし、[一般的なエラー処理のガイドライン](/works/otel-specs-ja/spec/error-handling/)にMUST従うものとします。

`SpanContext`はイミュータブルであるため、新しい`TraceState`で`SpanContext`を更新することはできないことに注意してください。このような変更は、[`SpanContext`の伝搬](/works/otel-specs-ja/spec/context/api-propagators/)や[テレメトリーデータのエクスポート](/works/otel-specs-ja/spec/trace/sdk/#spanexporter)の直前にのみ意味を持ちます。いずれの場合も、`Propagator`と`SpanExporter`は、ワイヤーへシリアライズする前に変更済みの`TraceState`のコピーを作成することがあります。

## Span

`Span`は、トレース内の単一の操作を表します。Spanは入れ子にしてトレースツリーを形成できます。各トレースにはルートスパンが含まれ、通常は操作全体を記述し、任意でそのサブ操作に対応する1つ以上のサブスパンを持ちます。

`Span`は以下をカプセル化します。

- スパン名
- `Span`を一意に識別するイミュータブルな[`SpanContext`](#spancontext)
- [`Span`](#span)、[`SpanContext`](#spancontext)、またはnullの形式による親スパン
- [`SpanKind`](#spankind)
- 開始タイムスタンプ
- 終了タイムスタンプ
- [`Attributes`](/works/otel-specs-ja/spec/common/#attribute)
- 他の`Span`への[`Link`](#link)のリスト
- タイムスタンプ付きの[`Event`](#add-events)のリスト
- [`Status`](#set-status)

*スパン名*は、Spanが表す作業を簡潔に識別します。例えばRPCメソッド名、関数名、より大きな計算の中のサブタスクやステージの名前などです。スパン名は、人間が読みやすい形を保ちつつ、個々のSpanインスタンスではなく（統計的に）興味深い*Spanのクラス*を識別する、最も一般的な文字列であるべきです（SHOULD）。つまり、"get_user"は妥当な名前ですが、"314159"がユーザーIDである"get_user/314159"は、高いカーディナリティのため良い名前ではありません。人間が読みやすいことよりも一般性がSHOULD優先されるものとします。

例えば、ある仮想的なアカウント情報を取得するエンドポイントの、想定されるスパン名を示します。

| スパン名 | 指針 |
| --------- | -------- |
| `get` | 一般的すぎる |
| `get_account/42` | 具体的すぎる |
| `get_account` | よい。account_id=42はSpanの属性として良い形になる |
| `get_account/{accountId}` | これもよい（「HTTPルート」を使っている） |

`Span`の開始と終了のタイムスタンプは、操作の実時間の経過を反映します。

例えば、あるspanがリクエスト・レスポンスのサイクル（HTTPやRPCなど）を表す場合、そのspanは最初のサブ操作の開始時刻に対応する開始時刻を持ち、最後のサブ操作が完了した時点の終了時刻を持つべきです。これには以下が含まれます。

- リクエストからのデータの受信
- データの解析（バイナリやJSON形式からなど）
- ミドルウェアや追加の処理ロジック
- ビジネスロジック
- レスポンスの構築
- レスポンスの送信

より詳細なオブザーバビリティが必要なサブ操作を表現するために、子スパン（場合によってはイベント）が作成される場合があります。子スパンは対応するサブ操作のタイミングを計測すべきであり、追加の属性を追加してもかまいません。

`Span`の開始時刻は、[span作成](#span作成)時の現在時刻にSHOULD設定されるものとします。`Span`が作成された後は、その名前を変更したり、`Attribute`を設定したり、`Event`を追加したり、`Status`を設定したりできるべきです（SHOULD）。これらは、`Span`の終了時刻が設定された後にMUST NOT変更されるものとします。

`Span`はプロセス内で情報を伝搬するために使われることを意図していません。誤用を防ぐため、実装は`SpanContext`以外の`Span`の属性へのアクセスをSHOULD NOT提供するものとします。

ベンダーは`Span`インターフェースを実装してベンダー固有のロジックを実現してもかまいません（MAY）。しかし、代替の実装は、呼び出し元が直接`Span`を作成することをMUST NOT許容するものとします。すべての`Span`は`Tracer`を介してMUST作成されるものとします。

### Span作成

[`Tracer`](#tracer)を使う以外に、`Span`を作成するAPIはMUST NOT存在するものとします。

暗黙の`Context`伝搬をサポートする言語では、`Span`の作成は、デフォルトで新しく作成された`Span`を[現在の`Context`](#コンテキストとの相互作用)内のアクティブな`Span`としてMUST NOT設定するものとしますが、この機能は追加で別の操作として提供してもかまいません（MAY）。

このAPIは以下のパラメータをMUST受け付けるものとします。

- スパン名。これは必須パラメータです。
- 親`Context`、または新しい`Span`がルート`Span`であるべきことを示す指示。APIは、デフォルトの動作として現在のContextを暗黙的に親として使うオプションを持ってもかまいません（MAY）。このAPIは、親として`Span`や`SpanContext`をMUST NOT受け付けるものとし、完全な`Context`のみを受け付けるものとします。

  Spanのセマンティックな親は、[コンテキストからの親スパンの決定](#コンテキストからの親スパンの決定)に記述されたルールに従ってMUST決定されるものとします。
- [`SpanKind`](#spankind)。指定されない場合のデフォルトは`SpanKind.Internal`です。
- [`Attributes`](/works/otel-specs-ja/spec/common/#attribute)。加えて、これらの属性は[サンプリングの説明](/works/otel-specs-ja/spec/trace/sdk/#サンプリング)に記載の通り、サンプリング判断に使われることがあります。指定されない場合は空のコレクションが想定されます。

  APIのドキュメントは、後から`SetAttribute`を呼び出すよりもspan作成時に属性を追加することが好ましいとMUST述べるものとします。SamplerはSpan作成時に既に存在する情報のみを考慮できるためです。

- `Link` - Linkの順序付きシーケンス。[APIの定義](#link)を参照。
- `開始タイムスタンプ`。デフォルトは現在時刻です。この引数は、span作成時刻が既に過去のものである場合にのみSHOULD設定されるものとします。APIがSpanの論理的な開始の時点で呼び出される場合、APIユーザーはこの引数を明示的にMUST NOT設定するものとします。

各スパンは0個か1個の親スパンと、0個以上の子スパンを持ち、これらは因果関係のある操作を表します。関連するスパンの木がトレースを構成します。親を持たないスパンは*ルートスパン*と呼ばれます。各トレースには単一のルートスパンが含まれ、これはトレース内の他のすべてのスパンの共通の祖先です。実装は、ルートスパンとして`Span`を作成するオプションをMUST提供するものとし、作成される各ルートスパンに対して新しい`TraceId`をMUST生成するものとします。親を持つSpanについては、`TraceId`は親と同じでなければなりません（MUST）。また、子スパンはデフォルトで親のすべての`TraceState`の値をMUST継承するものとします。

`Span`は、別のプロセスで作成された`Span`の子である場合、*リモートの親*を持つと言われます。各propagatorのデシリアライズは、親の`SpanContext`に対して`IsRemote`をtrueに設定しなければならず（MUST）、これにより`Span`作成時に親がリモートかどうかを認識できます。

作成されたすべてのspanは、MUST終了もされるものとします。これはユーザーの責務です。ユーザーがspanを終了させ忘れた場合、API実装はメモリやその他のリソース（例えば、すべてのspanを反復する定期的な処理のためのCPU時間を含む）をリークする場合があります（MAY）。

#### コンテキストからの親スパンの決定

新しい`Span`が`Context`から作成される場合、その`Context`には現在アクティブなインスタンスを表す`Span`が含まれることがあり、これが親として使われます。`Context`に`Span`が含まれない場合、新しく作成される`Span`はルートスパンになります。

`SpanContext`を`Context`に直接アクティブとして設定することはできませんが、[Spanへのラッピング](#spancontextのspanへのラッピング)によって設定できます。例えば、コンテキストの抽出を行う`Propagator`がこれを必要とすることがあります。

#### リンクの指定

`Span`作成時、ユーザーは他の`Span`へのリンクを記録できなければなりません（MUST）。リンクされる`Span`は同一トレースのものでも、異なるトレースのものでもかまいません -- [links](#link)を参照。Span作成時に追加された`Link`は、サンプリング判断のために[Sampler](/works/otel-specs-ja/spec/trace/sdk/#sampler)によって考慮されることがあります。

### Spanの操作

`Span`の`SpanContext`を取得する関数と`IsRecording`を除き、以下のいずれも`Span`が終了した後には呼び出せません。

#### Get Context

Spanインターフェースは以下をMUST提供するものとします。

- 指定された`Span`の`SpanContext`を返すAPI。返された値は、`Span`が終了した後でも使用できます。返された値は、Spanのライフタイム全体を通じてMUST同一であるものとします。これは`GetContext`と呼んでもかまいません（MAY）。

#### IsRecording

`Span`は、`SetAttributes`、`AddEvent`、`SetStatus`などの関数を通じて提供されたデータが何らかの形（例えばメモリ内）で捕捉される場合に記録中（`IsRecording`が`true`を返す）です。`Span`が記録中でない場合（`IsRecording`が`false`を返す）、このデータはすぐに破棄されます。データの設定や追加をさらに試みても記録されず、spanは実質的にno-opになります。

このフラグは、トレース全体がサンプリングされていない場合でも`true`になることがあります。これにより、バックエンドへ送信せずに個々のSpanに関する情報を記録・処理できます。このシナリオの例としては、SLA/SLOのレイテンシーチャートの処理・構築のためにすべての受信リクエストの記録と処理を行いつつ、そのうちの一部（サンプリングされたspan）だけをバックエンドへ送信する、といったケースが考えられます。[SDK設計のサンプリングの節](/works/otel-specs-ja/spec/trace/sdk/#サンプリング)も参照してください。

`Span`が終了した後は、それは記録中でなくなるべきであり（SHOULD）、`IsRecording`は常に`false`をSHOULD返すものとします。この唯一知られている例外は、ローカルな状態を保持せず、spanの終了後に`IsRecording`の値を変更できないストリーミング形式のAPI実装です。

`IsRecording`はパラメータをSHOULD NOT取るものとします。

このフラグは、spanが確実に記録されない場合にSpanの属性やイベントの計算コストの高い処理を避けるために使われるべきです（SHOULD）。子spanの記録は、このフラグの値（通常は[SpanContext](#spancontext)上の`TraceFlags`の`sampled`フラグに基づく）とは独立して決定されることに注意してください。

APIの利用者は、コードを計装する際にのみ`IsRecording`プロパティにアクセスすべきであり、コンテキストのpropagator内で使う場合を除き`SampledFlag`にアクセスすべきではありません。

#### Set Attributes

`Span`は、それに関連付けられた[`Attributes`](/works/otel-specs-ja/spec/common/#attribute)を設定する能力をMUST持つものとします。

Spanインターフェースは以下をMUST提供するものとします。

- 属性のプロパティが引数として渡される、単一の`Attribute`を設定するAPI。これは`SetAttribute`と呼んでもかまいません（MAY）。余分なメモリ確保を避けるため、実装によっては可能な値の型ごとに個別のAPIを提供することがあります。

Spanインターフェースは以下をMAY提供するものとします。

- `Attributes`が単一のメソッド呼び出しで渡され、複数の`Attributes`を一度に設定するAPI。

既存の属性と同じキーで属性を設定した場合、既存の属性の値をSHOULD上書きするものとします。

OpenTelemetryプロジェクトが、規定された意味を持つ["標準属性"](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/README.md)を文書化していることに注意してください。

[Sampler](/works/otel-specs-ja/spec/trace/sdk/#sampler)はSpan作成時に既に存在する情報のみを考慮できることに注意してください。後から行われる変更（新規または変更された属性を含む）は、そのSamplerの判断を変えることはできません。

#### Add Events

`Span`は、イベントを追加する能力をMUST持つものとします。イベントには、それが`Span`に追加された瞬間の時刻が関連付けられます。

`Event`は構造的に以下のプロパティによって定義されます。

- イベントの名前
- イベントのタイムスタンプ。イベントが追加された時刻、またはユーザーによって指定されたカスタムのタイムスタンプ
- イベントをさらに記述する、0個以上の[`Attributes`](/works/otel-specs-ja/spec/common/#attribute)

Spanインターフェースは以下をMUST提供するものとします。

- `Event`のプロパティが引数として渡される、単一の`Event`を記録するAPI。これは`AddEvent`と呼んでもかまいません（MAY）。このAPIは、イベントの名前、任意の`Attributes`、イベントが発生した時刻を指定するための任意の`Timestamp`を、個々のパラメータとして、あるいはそれらをカプセル化したイミュータブルなオブジェクトとして、言語にとって最も適切な形で受け取ります。ユーザーがカスタムのタイムスタンプを提供しない場合、実装はこのAPIが呼び出された時刻をイベントに自動的に設定します。

イベントは、記録された順序をSHOULD保持するものとします。これは通常イベントのタイムスタンプの順序と一致しますが、カスタムのタイムスタンプを使うことでイベントが順序通りでない形で記録されることもあります。

コンシューマーは、ユーザーがイベントやspanの開始・終了に対してカスタムのタイムスタンプを提供した場合、イベントのタイムスタンプがspanの開始前や終了後になる可能性があることに注意すべきです。提供されたタイムスタンプが範囲外である場合、この仕様書は正規化を要求しません。

OpenTelemetryプロジェクトが、規定された意味を持つ["標準的なイベント名とキー"](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/README.md)を文書化していることに注意してください。

[`RecordException`](#record-exception)は、例外イベントを記録するための`AddEvent`の特殊な変種であることに注意してください。

#### Add Link

`Span`は、作成後にそれに関連付けられた`Link`を追加する能力をMUST持つものとします - [Links](#link)を参照。Span作成後に追加された`Link`は、[Sampler](/works/otel-specs-ja/spec/trace/sdk/#sampler)によって考慮されない場合があります。

#### Set Status

`Span`の`Status`を設定します。これが使われた場合、デフォルトの`Span`ステータスである`Unset`を上書きします。

`Status`は構造的に以下のプロパティによって定義されます。

- `StatusCode`。以下に列挙する値のいずれか。
- `Status`を説明するメッセージを提供する任意の`Description`。`Description`は`Error`の`StatusCode`値とのみMUST併用されるものとします。空の`Description`は、指定されていない場合と等価です。

注: [OTLPプロトコルの定義](https://github.com/open-telemetry/opentelemetry-proto/blob/724e427879e3d2bae2edc0218fff06e37b9eb46e/opentelemetry/proto/trace/v1/trace.proto#L264)では、`Description`プロパティを`message`と呼んでいます。

`StatusCode`は以下のいずれかの値です。

- `Unset`
  - デフォルトのステータス。
- `Ok`
  - 操作がアプリケーション開発者やオペレーターによって、正常に完了したと検証されたことを示します。
- `Error`
  - 操作にエラーが含まれることを示します。

これらの値は`Ok > Error > Unset`という全順序を形成します。つまり、`StatusCode=Ok`で`Status`を設定すると、それ以前あるいはそれ以降に`StatusCode=Error`や`StatusCode=Unset`でspanの`Status`を設定しようとした試みを上書きします。より具体的なルールは以下を参照してください。

Spanインターフェースは以下をMUST提供するものとします。

- `Status`を設定するAPI。これは`SetStatus`とSHOULD呼ばれるものとします。このAPIは、`StatusCode`と任意の`Description`を、個々のパラメータとして、あるいはそれらをカプセル化したイミュータブルなオブジェクトとして、言語にとって最も適切な形で受け取ります。`StatusCode`が`Ok`や`Unset`の値の場合、`Description`はMUST無視されるものとします。

ステータスコードは、以下の状況を除いてSHOULD未設定のままとするものとします。

`Unset`値を設定しようとする試みはSHOULD無視されるものとします。

Instrumentation Libraryによってステータスが`Error`に設定される場合、`Description`はドキュメント化され予測可能であるべきです（SHOULD）。ステータスコードは、セマンティック規約で定義されたルールに従ってのみ`Error`に設定されるべきです。セマンティック規約が対象としない操作については、Instrumentation Libraryは、可能な`Description`の値とその意味を含む、独自の規約を公開すべきです（SHOULD）。

一般に、Instrumentation Libraryは、明示的にそう設定するよう構成されていない限り、ステータスコードを`Ok`に設定すべきではありません（SHOULD NOT）。Instrumentation Libraryは、上記のようにエラーがない限りステータスコードを`Unset`のままにすべきです（SHOULD）。

アプリケーション開発者やオペレーターは、ステータスコードを`Ok`に設定してもかまいません（MAY）。

spanのステータスが`Ok`に設定された場合、それは最終的なものとみなされるべきであり（SHOULD）、それ以降のいかなる変更の試みも無視されるべきです（SHOULD）。

分析ツールは、`Ok`ステータスに応じて、そうでなければ生成していたであろうエラーを抑制すべきです（SHOULD）。例えば、404のような煩雑なエラーを抑制するためです。

最後の呼び出しの値のみが記録され、実装は以前の呼び出しを自由に無視できます。

#### UpdateName

`Span`の名前を更新します。この更新を受けて、`Span`名に基づくいかなるサンプリングの振る舞いも実装に依存します。

[Sampler](/works/otel-specs-ja/spec/trace/sdk/#sampler)はSpan作成時に既に存在する情報のみを考慮できることに注意してください。更新されたspan名を含む、後から行われる変更は、そのSamplerの判断を変えることはできません。

名前更新の代替としては、最終的な`Span`名がわかった時点で、過去の明示的なタイムスタンプを指定してSpanを開始する遅延`Span`作成、あるいは望ましい名前を持つ`Span`を子`Span`として報告する、といった方法があります。

必須パラメータ:

- 新しい**スパン名**。`Span`開始時に渡された値を置き換えます。

#### End

このspanが記述する操作が、現時点（または任意で指定された時点）で終了したことを通知します。

実装は、`End`へのその後のすべての呼び出しと、その他のいかなるSpanメソッドの呼び出しもSHOULD無視するものとします。つまり、Spanは終了することで記録中でなくなります（Tracerがイベントをストリーミングしており、`Span`に関連する可変な状態を持たない場合には例外があるかもしれません）。

言語のSIGは、Pythonにおける`with`ステートメントのような言語固有の機能をサポートするために、spanを終了させる`End`以外のメソッドをAPIに提供してもかまいません（MAY）。しかし、そうしたメソッドのすべてのAPI実装は、内部で`End`メソッドをMUST呼び出すものとし、そうすることがドキュメント化されなければなりません（MUST）。

`End`は子スパンに対していかなる影響もMUST NOT持たないものとします。それらはまだ実行中である可能性があり、後で終了できます。

`End`は、それがアクティブになっているいかなる`Context`においても、その`Span`をMUST NOT非アクティブ化しないものとします。終了したspanを、それが含まれるContextを介して親として使用することは、依然として可能でなければなりません（MUST）。また、SpanをContextに入れるための仕組みはすべて、Spanが終了した後もMUST動作し続けるものとします。

パラメータ:

- （任意）終了タイムスタンプを明示的に設定するためのタイムスタンプ。省略された場合、これは現在時刻を渡した場合と同等にMUST扱われるものとします。

この操作は、本番アプリケーションの「ホットパス」で呼び出されることを想定してください。即座にとは言わないまでも、高速に完了するよう設計する必要があります。この操作自体は、呼び出し元のスレッドでブロッキングI/OをMUST NOT実行しないものとします。使用されるロックは最小限にとどめる必要があり、可能であれば完全に排除すべきです（SHOULD）。この操作から呼び出される一部の下流のSpanProcessorやそれに続くSpanExporterは、テスト、概念実証、デバッグのために使われるものであり、それら自体が本番用途向けに設計されていない場合があります。それらは、この要件と推奨の範囲には含まれません。

#### Record Exception

例外の記録を助けるため、その言語が例外を使う場合、言語はSHOULD `RecordException`メソッドを提供するものとします。これは[`AddEvent`](#add-events)の特殊な変種であり、ここで指定されていない事柄については`AddEvent`と同じ要件が適用されます。

このメソッドのシグネチャは各言語によって決められ、必要に応じてオーバーロードしてもかまいません（MAY）。このメソッドは、[exceptions](/works/otel-specs-ja/spec/trace/exceptions/)ドキュメントに概説された規約に従って、例外を`Event`としてMUST記録するものとします。必須の引数は、例外オブジェクトのみを超えないべきです（SHOULD）。

`RecordException`が提供される場合、そのメソッドは追加のイベント属性を提供するための任意のパラメータをMUST受け付けるものとします（これは`AddEvent`メソッドと同じ方法で行うべきです（SHOULD））。同じ名前を持つ属性がメソッドによって既に生成される場合、追加された属性が優先されます。

注: `RecordException`は、追加の例外固有のパラメータを持ち、他のすべてのパラメータが（例外セマンティック規約からのデフォルト値を持つため）任意である`AddEvent`の変種と見なせます。

### Spanのライフタイム

Spanのライフタイムは、開始と終了のタイムスタンプをSpanオブジェクトに記録するプロセスを表します。

- 開始時刻は、Spanが作成されたときに記録されます。
- 終了時刻は、操作が終了したときに記録される必要があります。

開始・終了時刻、およびEventのタイムスタンプは、対応するAPIが呼び出された時刻にMUST記録されるものとします。

### SpanContextのSpanへのラッピング

APIは、`Span`インターフェースを実装するオブジェクトで`SpanContext`をラップする操作をMUST提供するものとします。これは、プロセス内での`Span`の伝搬などの操作において、`SpanContext`を`Span`として公開するために行われます。

この操作をサポートするために新しい型が必要な場合、可能であればそれを公開すべきではありません（SHOULD NOT）（例えばSpanインターフェースの型を持つ何かを返す関数のみを公開することによって）。新しい型を公開する必要がある場合、それは`NonRecordingSpan`とSHOULD命名されるものとします。

振る舞いは以下のように定義されます。

- `GetContext`はラップされた`SpanContext`をMUST返すものとします。
- `IsRecording`は、イベント、属性、その他の要素が記録されていない、つまり破棄されていることを示すため`false`をMUST返すものとします。

`Span`の残りの機能はno-op操作としてMUST定義されるものとします。注: これには`End`も含まれます。したがって一般的なルールの例外として、そのようなSpanを終了させることは必須ではなく（有用でもありません）。

この機能はAPI内でMUST完全に実装されるものとし、オーバーライド可能であるべきではありません（SHOULD NOT）。

## SpanKind

`SpanKind`は、親子関係やspanリンクによって関連付けられたSpan間の関係を明確にします。`SpanKind`は、分析中にトレーシングシステムにとって有用な2つの独立したプロパティを記述します。

1. spanがリモートサービスへの発信呼び出し（`CLIENT`および`PRODUCER`スパン）を表すか、外部から開始された受信リクエストの処理（`SERVER`および`CONSUMER`スパン）を表すか。
2. Spanがリクエスト・レスポンス操作（`CLIENT`および`SERVER`スパン）を表すか、遅延実行（`PRODUCER`および`CONSUMER`スパン）を表すか。

`SpanKind`が意味を持つようにするため、呼び出し元は単一のSpanが2つ以上の目的を果たさないようにSHOULD配慮するものとします。例えば、サーバー側のspanは、発信するリモートプロシージャコールを記述するために使うべきではありません（SHOULD NOT）。簡単な指針として、計装はリモートの発信呼び出しに対して`SpanContext`を注入する前に新しいSpanを作成すべきです。

注: 機能を提供する様々なコンポーネントがどのように構築・計装されているかによっては、`CLIENT`スパンが同じく`CLIENT`スパンである子を持つことや、`PRODUCER`スパンが`CLIENT`スパンであるローカルな子を持つことがあります。

特定の技術に対する[セマンティック規約](../../overview/#セマンティック規約)は、それらが定義する各spanについて種別を文書化すべきです（SHOULD）。

例えば、[データベースクライアントのセマンティック規約](https://opentelemetry.io/docs/specs/semconv/db/database-spans/)は、データベース呼び出しを記述するために`CLIENT`のspan種別を使うことを推奨しています。データベースクライアントがサーバーとHTTP経由で通信する場合、HTTP計装（有効な場合）は、論理的なデータベース`CLIENT`操作の範囲内で実行される個々のHTTP呼び出しを追跡するために、入れ子になった`CLIENT`スパンを作成します。

以下は、`SpanKind`として可能な値です。

* `SERVER`は、そのspanがクライアントがレスポンスを待っている間のリモートリクエストのサーバー側処理を対象としていることを示します。
* `CLIENT`は、そのspanがクライアントがレスポンスを待っているリモートサービスへのリクエストを記述していることを示します。`CLIENT`スパンのコンテキストが伝搬されると、`CLIENT`スパンは通常リモートの`SERVER`スパンの親になります。
* `PRODUCER`は、そのspanがローカルまたはリモートの操作の開始やスケジューリングを記述していることを示します。この開始側のspanは、対応する`CONSUMER`スパンが開始する前であっても、それより先に終了することがよくあります。

  バッチ処理を伴うメッセージングのシナリオでは、個々のメッセージをトレースするために、メッセージごとに新しい`PRODUCER`スパンを作成する必要があります。
* `CONSUMER`は、そのspanが、プロデューサーが結果を待たない形で開始された操作の処理を表していることを示します。
* `INTERNAL` デフォルト値。リモートの親や子を持つ操作とは異なり、そのspanがアプリケーション内部の操作を表していることを示します。

これらの種別の解釈を以下にまとめます。

| `SpanKind` | 呼び出しの方向 | コミュニケーションの形式 |
|------------|----------------|---------------------|
| `CLIENT`   |   発信     |   リクエスト・レスポンス  |
| `SERVER`   |   受信     |   リクエスト・レスポンス  |
| `PRODUCER` |   発信     |  遅延実行 |
| `CONSUMER` |   受信     |  遅延実行 |
| `INTERNAL` |                |                     |

## Link

ユーザーは、他の`SpanContext`へのリンクを記録する能力をMUST持つものとします。リンクされる`SpanContext`は、同一トレースのものでも、異なるトレースのものでもかまいません -- [Links between spans](../../overview/#スパン間のリンク)を参照。

`Link`は構造的に以下のプロパティによって定義されます。

- リンク先の`Span`の`SpanContext`。
- リンクをさらに記述する、0個以上の[`Attributes`](/works/otel-specs-ja/spec/common/#attribute)。

APIは以下をMUST提供するものとします。

- `Link`のプロパティが引数として渡される、単一の`Link`を記録するAPI。これは`AddLink`と呼んでもかまいません（MAY）。このAPIは、リンク先の`Span`の`SpanContext`と任意の`Attributes`を、個々のパラメータとして、あるいはそれらをカプセル化したイミュータブルなオブジェクトとして、言語にとって最も適切な形で受け取ります。実装は、属性の集合か`TraceState`のいずれかが空でない限り、空の`TraceId`や`SpanId`（すべてゼロ）を持つ`SpanContext`を含むリンクをSHOULD記録するものとします。

Spanインターフェースは以下をMAY提供するものとします。

- `Link`が単一のメソッド呼び出しで渡され、複数の`Link`を一度に追加するAPI。

Spanは`Link`が設定された順序をSHOULD保持するものとします。

APIのドキュメントは、span作成時に利用可能なコンテキストについては、後から`AddLink`を呼び出すよりもspan作成時にリンクを追加することが好ましいとMUST述べるものとします。ヘッドサンプリングの判断は、span作成時に存在する情報のみを考慮できるためです。

## 並行性の要件

並行実行をサポートする言語について、トレーシングAPIは特定の保証と安全性を提供します。すべてのAPI関数が並行して呼び出すことに対して安全というわけではありません。

**TracerProvider** - すべてのメソッドは、実装がデフォルトで並行使用に対して安全である必要があるとMUSTドキュメント化されるものとします。

**Tracer** - すべてのメソッドは、実装がデフォルトで並行使用に対して安全である必要があるとMUSTドキュメント化されるものとします。

**Span** - すべてのメソッドは、実装がデフォルトで並行使用に対して安全である必要があるとMUSTドキュメント化されるものとします。

**Event** - Eventはイミュータブルであり、デフォルトで並行使用に対してMUST安全であるものとします。

**Link** - Linkはイミュータブルであり、デフォルトで並行使用に対してSHOULD安全であるものとします。

## 含まれるPropagator

propagatorがどのように配布されるかについては、[Propagators Distribution](/works/otel-specs-ja/spec/context/api-propagators/#propagators-distribution)を参照してください。

## SDKが存在しない場合のAPIの振る舞い

一般に、SDKがインストールされていない場合、Trace APIは「no-op」なAPIです。これは、TracerやSpanに対する操作は副作用を持たず、何も行わないべきであることを意味します。しかし、この一般的なルールには1つ重要な例外があり、それは`SpanContext`の伝搬に関連するものです。APIは、（明示的に与えられたか暗黙の現在のものかにかかわらず）親`Context`内の`SpanContext`を持つ非記録の`Span`をMUST返すものとします。親`Context`内の`Span`が既に非記録である場合、新しい`Span`をインスタンス化せずに直接それをSHOULD返すものとします。親`Context`に`Span`が含まれない場合、代わりに空の非記録Spanが（すなわち、すべてゼロのSpanおよびTrace ID、空のTracestate、サンプリングされていないTraceFlagsを持つ`SpanContext`を持つものが）MUST返されるものとします。これは、設定された`Propagator`によって提供された`SpanContext`がすべての子spanへ伝搬され、最終的に`Inject`にも伝わりますが、新しい`SpanContext`は作成されないことを意味します。

