> Source: https://www.ymotongpoo.com/works/oteps/otep-0182/


# OTEP-0182: OTLPにおけるSpanContext.IsRemoteのエクスポート

スパンの親がリモートかどうかを示すよう、OTLPを更新します。

## 動機 {#motivation}

エントリーポイントのスパン、すなわち親を持たないスパン（トレースのルート）、またはリモート親を持つスパンのみを後処理したり可視化したりすることが有用な場合があります。
たとえば、Elastic APMのソリューションはエントリーポイントのスパンをハイライトし（Elastic APMはこれらを「トランザクション」と呼びます）、これらをユーザーインターフェース上のトップレベルの操作として表示します。

目標は、完全な分散トレースをDAG（有向非巡回グラフ）として組み立てることなく、サービスに入ってくる、あるいはサービス内で発生したリクエストを表すスパンを識別することです。
トレースのルートを識別することは容易ですが、リモート親を持つスパンを識別することはできません。

以下は、エントリーポイントのスパンに枠線を付けた、作為的な分散トレースの例です。

```mermaid
graph TD
    subgraph comments_service
    POST_comments(POST /comment)
    POST_comments --> comments_send(comments send)
    end

    subgraph auth_service
    POST_comments --> POST_auth(POST /auth)
    POST_auth --> LDAP
    end

    subgraph user_details_service
    POST_comments --> GET_user_details(GET /user_details)
    GET_user_details --> SELECT_users(SELECT FROM users)
    end

    subgraph comments_inserter
    comments_send --> comments_receive(comments receive)
    comments_receive --> comments_process(comments process)
    comments_process --> INSERT_comments(INSERT INTO comments)
    end

    style POST_comments stroke-width:4
    style POST_auth stroke-width:4
    style GET_user_details stroke-width:4
    style comments_receive stroke-width:4
```

## 解説 {#explanation}

スパンのOTLPエンコーディングには、スパンの親がリモートかどうかを識別するためのブール値の `parent_span_is_remote` フィールドがあります。
すべてのOpenTelemetry SDKがこのフィールドを設定し、バックエンドはこれを使ってスパンをエントリーポイントのスパンとして識別できます。
スパンは、親を持たない場合（`parent_span_id` が空の場合）、または `parent_span_is_remote` が真である場合に、エントリーポイントのスパンとみなすことができます。

## 内部の詳細 {#internal-details}

最初の部分は、トレースのprotobufを更新し、[`Span` メッセージ](https://github.com/open-telemetry/opentelemetry-proto/blob/b43e9b18b76abf3ee040164b55b9c355217151f3/opentelemetry/proto/trace/v1/trace.proto#L84)に `boolean parent_span_is_remote` フィールドを追加することです。

[`SpanContext.IsRemote`](../specification/trace/api.md#isremote)は、スパンコンテキストがリモート親から伝播されたかどうかを識別します。
各SDKのOTLPエクスポーターは、これを新しい `parent_span_is_remote` フィールドに記録するように更新される必要があります。

古いOTLPバージョンとの後方互換性のため、protobufフィールドは `nullable`（`true`、`false`、または未指定）でなければならず、opentelemetry-collectorのprotogenコードは、バックエンドのエクスポーターがこのフィールドが設定されているかどうかを識別できるAPIを提供する必要があります。

```go
package pdata

// ParentSpanIsRemote indicates whether ms's parent span is remote, if known.
// If the parent span remoteness property is known then the "ok" result will be true,
// and false otherwise.
func (ms Span) ParentSpanIsRemote() (remote bool, ok bool)
```

## トレードオフと緩和策 {#trade-offs-and-mitigations}

特に識別されていません。

## 先行技術と代替技術 {#prior-art-and-alternatives}

### 代替案1: 他のスパンにエントリーポイントのスパンIDを含める {#alternative-1-include-entry-point-span-id-in-other-spans}

親スパンがリモートかどうかを識別する代わりに、すべての非エントリーポイントのスパンにエントリーポイントのスパンのIDをエンコードして伝播するという方法も考えられます。
これにより、このフィールドがないことでエントリーポイントのスパンを識別できます。

エントリーポイントのスパンIDは、リモート親を持つスパンを開始するときに取得され、`SpanContext` を通じて伝播されます。
`Span` のprotobufメッセージ定義に新しい `entry_span_id` フィールドを導入し、OTLPエクスポーターでこれを設定します。

これはもともと[OpenCensusで提案されました](https://github.com/census-instrumentation/opencensus-specs/issues/229)が、決着はついていません。

この代替案の欠点は次のとおりです。

- `SpanContext` を拡張してエントリーポイントのスパンIDを含める必要があり、SDKはこれを取得・伝播するように更新される必要があります
- 追加のprotobufフィールドは、ブール値フィールドの1バイトに対して、追加で8バイトになります

このアプローチの主な利点は、バックエンドがプロセスのサブグラフによってスパンをグループ化できるようになることです。

### 代替案2: エントリーポイントのスパンを識別するためのセマンティック規約の属性を導入する {#alternative-2-introduce-a-semantic-convention-attribute-to-identify-entry-point-spans}

スパンに新しいフィールドを追加する代わりに、エントリーポイントのスパンのみに新しいセマンティック規約の属性を追加するという方法も考えられます。

このアプローチはすべてのスパンのメモリフットプリントの増加を避けられますが、エントリーポイントのスパンについてはより大きなメモリフットプリントになります。
したがって、このアプローチの利点は、エントリーポイントのスパンと内部スパンの比率に依存し、場合によってはむしろコストが高くなる可能性もあります。

### 代替案3: SpanKindの値を拡張する {#alternative-3-extend-spankind-values}

もう一つの代替案は、SpanKindの値を拡張して、CONSUMERスパンがリモート親を持つかローカル親を持つかを曖昧さなく定義することです（たとえば、メッセージのポーリングのユースケースで）。

たとえば、SpanKindの`Remote-Incoming`プロパティに対して明確に「いいえ」となる新しいSpanKind（たとえば `AMBIENT_CONSUMER`）を導入し、`REMOTE_CONSUMER` はSpanKindの`Remote-Incoming`プロパティに対して明確に「はい」となるようにします。
このアプローチの欠点は、`CONSUMER` スパンのセマンティクスに対する破壊的変更になることです。

## 未解決の問題 {#open-questions}

### `parent_span_is_remote` と `SpanKind` の関係 {#relation-between-parent_span_is_remote-and-spankind}

`SpanKind` の仕様は次のように説明しています。

```
The first property described by SpanKind reflects whether the Span is a "logical" remote child or parent ...
```

しかし、仕様は `CONSUMER` スパンの種類に関して、この「論理的な」リモート親のプロパティについて曖昧なままです。
それにもかかわらず、提案されているフィールド `parent_span_is_remote` は、その `SpanKind` のプロパティといくらか重複しています。
仕様は `SpanKind` とその `parent_span_is_remote` との関係について、いくらかの明確化が必要になるでしょう。

## 今後の課題 {#future-possibilities}

他に識別されている今後の変更はありません。

