# 自己オブザーバビリティ 補足ガイドライン

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/self-observability-supplementary-guidelines/


注記: この文書は仕様ではありません。[自己オブザーバビリティ](/works/otel-specs-ja/spec/self-observability/)仕様を補うために提供されるものであり、既存の仕様に何ら追加の要求事項を加えるものではありません。

## シグナルの範囲とライフサイクルの順序

SDKの自己オブザーバビリティは現在、[SDK自己オブザーバビリティメトリクスセマンティック規約][semconv-sdk-metrics]で定義されている通り、主にメトリクスとして表現されています。この設計は本質的にメトリクスだけに限定されるものではありません。SDK内部を記述するイベントやスパンが、将来のセマンティック規約によって追加される可能性があるため、SDKの実装者は、この表面が今後もメトリクスの形のままであると仮定すべきではありません。

[semconv-sdk-metrics]: /works/otel-specs-ja/semconv/otel/sdk-metrics/

複数のシグナルが関わるようになると、ライフサイクルの順序が問題になります。記録を担うプロバイダー（`MeterProvider`、`LoggerProvider`、場合によっては`TracerProvider`）は個別に構築・シャットダウンされるため、2番目に構築されるプロバイダーは、1番目のプロバイダーのセットアップ中に生成されたテレメトリーを受け取れません。同様に、あるプロバイダーがシャットダウンされると、他のプロバイダーがまだ終了処理中であっても、そのプロバイダーはテレメトリーをそれ以上受け取れなくなります。

例えば、起動時には以下のようになります。

* `MeterProvider`が最初に構築される場合、そのセットアップ中に生成される自己オブザーバビリティの*イベント*は、`LoggerProvider`がまだ存在しないため、`LoggerProvider`を通じてはまだ流せません。
* `LoggerProvider`が最初に構築される場合、そのセットアップ中に生成される自己オブザーバビリティの*メトリクス*は、`MeterProvider`を通じてはまだ流せません。

どのような順序にしても、この問題を完全には回避できません。「2番目」に立ち上がるプロバイダーは、自身が存在する前の期間を失い、「最初」にシャットダウンされるプロバイダーは、自身が消えた後の期間を失います。したがって、SDKのライフサイクルの端に位置する自己オブザーバビリティのテレメトリーは、本質的にベストエフォートであり、その扱い方の方針はSDKに委ねられます。

自己オブザーバビリティの[イベント](/works/otel-specs-ja/spec/logs/data-model/#events)に特化した話として、SDKが既に非OpenTelemetry経路（その言語のネイティブなロギング機構、よく使われるエコシステムのロギングライブラリ（RustのTokioの`tracing`クレートなど）、あるいは最も単純な場合にはstdout/stderrへの直接書き込み）で診断情報を出力しているなら、その経路は、`LoggerProvider`がインストールされる前や、シャットダウンされた後に発生するイベントにとって自然な選択肢になります。この経路は通常、プロセスの生存期間全体で利用可能であり、失敗しうる外部依存もほとんどありません。

そのようなイベントであっても、そのイベント名は必要です。その仕組みにネイティブなイベント名フィールドがあれば（.NETの`ILogger`やRustの`tracing`にはあります）それを使い、なければ、安定版の[`otel.event.name`](https://opentelemetry.io/docs/specs/semconv/registry/attributes/otel/#otel-event-name)属性として運びます。この属性は、CollectorやバックエンドによってLogRecordの`EventName`に対応付けることができます。

## 自己オブザーバビリティ用のMeter・Loggerの取得

SDKが自己オブザーバビリティのテレメトリーを発行するために使う`Meter`・`Logger`を取得する方法には、大きく異なる2つの方式があります。

* グローバルプロバイダーから取得する方法（例: `GlobalMeterProvider.Get(...)`）。この場合、自己オブザーバビリティのデータは、ユーザーの他のテレメトリーと同じパイプラインを流れます。これは実装が最も簡単で、追加の設定を必要としません。トレードオフは、ユーザーがSDKの自己オブザーバビリティだけを別に振り分けにくくなることと、SDKが自身のパイプラインへテレメトリーを発行することになるため、[テレメトリーがテレメトリーを誘発する懸念](#テレメトリー誘発によるテレメトリーループの回避)がより重要になることです。
* ユーザーから明示的に（通常は専用の設定オプションを通じて）渡された`MeterProvider`・`LoggerProvider`から取得する方法。これにより[別パイプライン](#テレメトリー誘発によるテレメトリーループの回避)を使う方式が可能になり、オペレーターはSDKの自己オブザーバビリティを別のバックエンドへ送ったり、異なる保持期間・サンプリングを適用したりできます。トレードオフは、設定面が増えることと、プロバイダーが渡されない場合のフォールバックの判断（グローバルへフォールバックするか、何も発行しないかなど）が必要になることです。

どちらの選択も有効であり、SDKの対象読者と、別経路への振り分けをどれだけ強く実現したいかに依存します。

これら2つの方式は組み合わせることもできます。SDKは、明示的な`MeterProvider`・`LoggerProvider`を受け付け、渡されなかった場合はグローバルへフォールバックできます。これは計装ライブラリでよく見られるパターンであり、追加の設定を必要としないユーザーに強制することなく、オペレーターにSDKの自己オブザーバビリティを別経路へ振り分ける選択肢を与えます。

## テレメトリー誘発によるテレメトリーループの回避

SDKが自身のテレメトリーパイプラインを通じて自己オブザーバビリティのデータを発行すると、その発行したデータが同じパイプラインによってさらに処理され、フィードバックループを生む可能性があります。これは主にイベントとトレースにおいて問題になります。SDKがイベントやスパンを処理する際に生成する各イベント・スパンが、それ自体さらなるイベント・スパンを生み出し、無制限の再帰につながる可能性があるためです。メトリクスは実際上、この影響を受けにくいです。

このようなループを防ぐためにSDKが使えるパターンには、以下のものがあります。

* 自己オブザーバビリティ用に、ユーザーのパイプラインから分離された専用の`LoggerProvider`（または`TracerProvider`）を使い、自己オブザーバビリティのテレメトリーがそのパイプラインへフィードバックしないようにする。
* OpenTelemetryの`Context`を使って、コードがSDK自身のパイプライン内で実行されていることを示すフラグを運び、そのフラグが立っているときは自己オブザーバビリティの記録をスキップする。これに関する標準化された仕様は現時点では存在しません（[open-telemetry/opentelemetry-specification#530](https://github.com/open-telemetry/opentelemetry-specification/issues/530)で追跡されています）。その間、複数のSDKが独自にこれを実装しています。
  * .NET:
    [`SuppressInstrumentationScope`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/core-1.15.3/src/OpenTelemetry/SuppressInstrumentationScope.cs#L12)
  * Rust:
    [`Context::enter_telemetry_suppressed_scope`](https://github.com/open-telemetry/opentelemetry-rust/blob/opentelemetry-0.32.0/opentelemetry/src/context.rs#L410)
  * Python:
    [`_SUPPRESS_INSTRUMENTATION_KEY`](https://github.com/open-telemetry/opentelemetry-python/blob/v1.42.1/opentelemetry-api/src/opentelemetry/context/__init__.py#L152)
  * Java:
    [`InstrumentationUtil.suppressInstrumentation`](https://github.com/open-telemetry/opentelemetry-java/blob/v1.63.0/api/all/src/main/java/io/opentelemetry/api/impl/InstrumentationUtil.java#L23-L24)

## 自己オブザーバビリティを他のSDK機能と同様の安定性で扱う

SDKの自己オブザーバビリティはSDKの機能の1つであり、他のSDK機能と同じ[安定性の保証](/works/otel-specs-ja/spec/versioning-and-stability/)の対象になります。弱められることも、扱いが異なることもありません。

これには3つの結果が伴います。

1. 開発中または実験的なメトリクス・属性・セマンティクスは、オプトインでなければなりません。
2. 表面の一部が安定版で一部が実験的である場合、安定版の部分だけをデフォルトで有効にし、実験的な部分はオプトインのままにすべきです。
3. 自己オブザーバビリティは「単なる診断データだから」という理由でこれらのルールから免除されません。SDK機能の安定性ルールは一律に適用され、破壊的変更は破壊的変更です。

オプトインをどのように公開するかは各SDKに委ねられています。既存のSDKの例としては以下のものがあります。

* SDKの実験的機能の命名規則を使った環境変数（例えば、OpenTelemetry Goの`OTEL_GO_X_OBSERVABILITY`）。
* ビルド時のフィーチャーフラグ（例えば、OpenTelemetry Rustにおける実験的なCargoフィーチャー）。

