この記事は英語の原文を日本語に翻訳したものです。原文: https://opentelemetry.io/docs/specs/semconv/how-to-write-conventions/resource-and-entities/

翻訳元: open-telemetry/semantic-conventions v1.44.0(コミット e10a930

リソースとEntity

モデリングガイド

Entityを定義するには、グループ種別をentityとして、新しいセマンティック規約のモデルファイルを作成します。例えば次のとおりです。

model/{my_domain}/entities.yaml:

groups:
  - id: entity.my_entity
    type: entity
    stability: development
    name: my_entity
    brief: >
      A description of my_entity here.
    attributes:
      - ref: some.attribute
        role: identifying
      - ref: some.other_attribute
        role: descriptive
        ...

ここで、attributesフィールドにはEntityのすべての属性が含まれます。 各属性のroleは、それが識別属性か記述属性かを決めます。これらの意味の詳細については、識別属性の定義方法を参照してください。

[!Note] Entity間の関係の宣言は、まだサポートされていません。

シグナル間の関連の宣言

特定のオブザーバビリティシグナルとともに使用すべきEntityを宣言できます。例えば、プロセスメトリクスは、そのメトリクスが既知のプロセスに関連付けられるように、processエンティティとともに使用すべきです。これを宣言するには、シグナルのentity_associationsフィールドを使い、別のリソースグループを名前で参照します。

model/{my_domain}/metrics.yaml:

groups:
  - id: metric.some_metric
    type: metric
    ...
    entity_associations:
      - my_entity

注:

  • 安定版のシグナルから未安定なリソースに関連を宣言することはできません。
  • 複数の関連を宣言できます。これらは「1つまたは複数」の集合を形成し、名前を挙げたEntityのうち1つまたは複数がそのメトリクスに関連付けられる場合があります。1つのシグナルに1つだけEntityを付ける必要はありません。

Entityの拡張

セマンティック規約では推奨されませんが、追加の記述属性を含むEntityの新しい「ビュー」を定義できます。そのためには、グループのextendsフィールドを使います。

model/{my_other_domain}/entities.yaml:

groups:
  - id: entity.my_entity_2
    type: entity
    extends: entity.my_entity
    attributes:
      - ref: new.attribute.name
        requirement_level: opt_in
        role: descriptive

注:

  • 新しいEntityのnametypeフィールドを変更することはできません。
  • 識別属性の集合を変更することはできません。

FAQ

新しいEntityをいつ定義すべきか

Entityを定義すべきシナリオは2つあります。

  • 新しいシグナル(ログ、メトリクス、スパンなど)を生成していて、「源」として意味をなす既存のEntityがない場合。
  • (将来)記録システム(Kubernetesのリソースやクラウドのアセットなど)から、Entityの階層を記述する必要がある場合。

例えば、新しいクラスタリングソリューション(HashicorpのNomadなど)が定義され、既存のコンテナベースのEntityでは不十分な場合、新しいEntityを定義すべきです。

「is-a」関係とは何か

OpenTelemetryは、オープンなエコシステムであるため、世の中に存在しうるすべてのEntityを理解しモデル化することはできません。そのため、領域をまたいで重複する定義を許容しています。例えば、containerk8s.containerというEntityは両方とも存在し、一般にすべてのk8s.containercontainerですが、すべてのcontainerがKubernetes上で動作するわけではありません。

「is-a」関係は、あるEntityが、異なる領域から見た別のEntityとまったく同じシステムコンポーネントを記述していることを表します。上の例では、k8s.containerはKubernetes領域からのコンテナをモデル化し、containerは、それがどのように実行されるか(podman、Docker、Kubernetes、FAASなど)にかかわらないコンテナの汎用モデルです。

「is-a」関係は、Entity間のこの関係を表すことで、OpenTelemetryがEntityの部分集合(既知のすべてのk8sリソースをEntityとしてなど)を完全にモデル化できるようにしつつ、将来新しいEntityとともに拡張されたエコシステムが成長・進化できるようにします。

「is-a」関係と記述属性の拡張、どちらを定義すべきか

重要な規則は2つあります。

  • 明確な「is-a」(またはそれに類する)関係を持つ、別々のEntityを導入することを既定とします。
  • 次のことが両方とも成り立つ場合に限り、新しい記述属性でEntityを拡張します。
    • 拡張するEntityが単独では、どのテレメトリーとも関連付けられない。
      • 例1: windows.processエンティティを追加する場合、windows.processに固有のプロセスメトリクスやログを新たに作成することは想定しておらず、代わりにすべてのデータはprocessエンティティに対して報告され続けます。
      • 例2: docker.containerエンティティを追加する場合、コンテナ固有のシグナルを新たに作成することは想定しておらず、代わりにログ、メトリクス、スパンはcontainerエンティティに対して報告されます。
    • 拡張するEntityが、論理的にそのEntityとだけ関連付けられる他のEntityを持たない。 注: これは、関係を持つシグナルとしてのEntityにのみ当てはまります。

これにより、サブタイプ化の複雑さや、属性の使い方が曖昧になる問題を避けられます。

識別属性の定義方法

識別属性は、そのEntityがどのように発見されるかという文脈の中で、そのEntityを識別するために必要十分な最小限のものであるべきです。例えばk8s.podk8s.deploymentのようなKubernetesのEntityを発見する場合、識別属性は、Kubernetesクラスタの範囲内(より具体的には、そのEntityを発見するKubernetes APIサーバーの範囲内)でこれらのEntityを識別するのに十分であるべきです。

一般に、テレメトリーの生成側が識別情報を組み立てる際に利用できる属性は多数あります。利用可能な属性のうち、EntityのIDには、そのEntityを一意に識別するのに十分な最小限の属性の集合を含めるべきです。例えばホスト上のプロセスは、(process.pidprocess.creation.time)の属性によって一意に識別できます。例えばprocess.executable.name属性を識別情報に加えることは不要であり、必要十分な識別情報という規則に違反します。

識別属性は、一般にそのEntityの寿命を形成します。これは特に、あるEntityに対して記録されるメトリクスにとって重要です。この寿命によって、報告される点の間で時系列が「接続」されたままになるか、それとも突然のドロップのように見えるかが決まります。重要なアラートやモニタリングの用途では、寿命を「安定」させ続けるような識別情報を選ぶことが推奨されます。

識別属性は、そのEntityの寿命の間に変化してはなりません(MUST NOT)。

複数のObserverに関するガイダンス

識別属性を選ぶ際は、複数のObserverが同じEntityに対して同じ識別属性を見出せるように注意すべきです。一般に、EntityはOpenTelemetry SDKとCollectorの両方で発見される可能性があり、これらのシグナル提供元の間で同じになる識別属性を活用すべきです。

例えばservice.instance.idは、SDKの外側と内側で一貫して検出することが難しい場合があります。一般に、これは、外部のソースがSDKに対して外部から可視なservice.instance.idの値を注入する場合にのみ実現できます。代替案として、SDKがservice.instance.idと、外部から可視な別のEntityとの間の関係を提供するという方法もあります。Entityをモデル化する際は、可能な限りこの問題を避けるように注意してください。

service.instance.idの選択は、モデル化される大半のEntityにとって例外であるべきであり、原則ではありません。サービスのインスタンス化はOpenTelemetryの基本的な機能であり、これは重要な「フォールバック」の識別情報だと私たちは考えています。これは、すべてのObserverで共有される1つのID生成元がある場合に最もうまく機能します。しかし実際には、次のようなシナリオでは、これは困難であるか「標準的でない」ものになります。

  • プッシュ型のOTLPデータ上のservice.instance.idと一致するinstanceラベルを求める、Prometheusのプル型メトリクス。
  • k8s.nodeからコンテナログを読み取る場合。コンテナ名とデプロイメントは分かりますが、SDKの内部を見ることができず、選ばれたインスタンスIDを把握できません。

OpenTelemetry Operatorや、Kubernetes向けのオンボーディングガイドなどは、service.instance.idをSDKと外部のObserverまで確実に伝播させる仕組みを活用しており、Kubernetesにおけるこの摩擦を緩和しています。

Entityの名前空間の付け方

Entity(型と属性の両方)は、そのEntityを識別するために使われる主要な仕組みを軸に名前空間化すべきです。例えばKubernetesのEntityはk8s名前空間を使い、主にKubernetes APIを使って、あるいはKubernetes内で作業することで発見されます。

セマンティック規約の名前空間化の全体的な規則については、一般的な命名ガイダンスを参照してください。

背景: リソースとEntity

OpenTelemetryでは、すべてのシグナルはResourceに関連付けられます。仕様書によると、これは次のように定義されています。

Resourceは、テレメトリーを生成するEntityの表現です。OpenTelemetry内では、すべてのシグナルがResourceに関連付けられ、同じ源から得られるデータをコンテキストに基づいて関連付けられるようにします。例えば、あるスパンで高いレイテンシーを見つけた場合、そのレイテンシーが観測された時間帯に、同じEntityが生成した他のメトリクスも確認する必要があります。

Resourceはオブザーバビリティにとって2つの重要な側面を提供します。

  • テレメトリーを生成しているEntityを識別しなければなりません(MUST)。
  • ユーザーがそのEntityがインフラのどこにあるかを判断できるようにすべきです(SHOULD)。

すべてのリソースは、Entityから構成されます。 Entityは次のように規定されています。

Entityは、生成されるテレメトリー(トレース、メトリクス、ログ、プロファイルなど)に関連付けられる、関心の対象となるオブジェクトを表します。

EntityとResourceの定義には重なりがありますが、両者にはいくつかの重要な違いがあります。

  • Entityは既知の「型」(servicek8s.podhostなど)を持ちます。
  • Entityは、識別属性と記述属性を区別できます。
    • 識別属性は、あるシステム内でそのEntityを識別するために使用できます(必要十分な識別情報を参照してください)。例えばk8s.pod.uidは、Kubernetes内のpodの識別属性とみなされます。
    • 記述属性は、Entityに追加のラベルを提供するために使用できますが、そのEntityを一意に識別するためには必要ありません。
  • Resourceは複数のEntityから構成されます。
    • Resourceに含まれる各Entityは、そのテレメトリーに「寄与」しているとみなされます。
    • 例えば現在、多くのSDKはserviceエンティティに加えて、k8s.containerhostのような別のEntityも含んでいます。
  • あるEntityは、別のEntityと概念的に類似している場合があります(これを「is-a」関係と呼びます)。
    • 例えばk8s.clusterエンティティはKubernetesクラスタを汎用的に表しますが、aws.eks.clusterエンティティは、AWS固有の概念であるElastic Kubernetes Clusterを表します。
    • この場合、EKSからのResourceには、aws.eks.clusterエンティティとk8s.clusterエンティティの両方が含まれる可能性があります。

OpenTelemetryにおけるEntityとResourceにとって重要な、2つの重要な原則があります。

  1. オープンな拡張: OpenTelemetryの外部のユーザーが、システム内でEntityの定義と関係を提供できるようにすること。
  2. テレスコーピングされた識別情報: 重要なクエリ(アラートやダッシュボードなど)を最適化するために、オブザーバビリティデータの柔軟な非正規化を許容すること。

オープンな拡張

OpenTelemetryは、オープンなシステムとして設計されています。システム内のEntityと関係の中核的な集合を定義する際には、これらのEntityと可能な関係が何であるかについて、オープンであり続ける必要があります。ユーザーが持つあらゆるシステムは、既存のOpenTelemetryセマンティック規約をモデル化し、それに参加できるべきです。これは、次の2つの重要な側面によって実現されます。

  • 名前空間化
  • 「is-a」関係

OpenTelemetryセマンティック規約内で新しいEntityの集合を定義する際は、セマンティック規約の命名ポリシーに従って名前空間化すべきです。これにより、どの概念が互いに明確に関連しているかを明示できます。例えばk8s名前空間は、Kubernetes関連のEntityとその関係を定義します。ユーザーは、k8sの上に概念をモデル化する際に、新しい名前空間を作成すべきだと分かります。

既存の概念への拡張は、「is-a」関係によって行われます。これは、あるEntityが、何らかの新しいスコープ付きの文脈の中で、別のEntityと同じ概念を表すことが分かっている関係です。例えばaws.eks.clusterk8s.clusterですが、すべてのk8s.clusterエンティティがaws.eks.clusterエンティティであるわけではありません。

テレスコーピングされた識別情報

OpenTelemetry内では、ユーザーに対して、オブザーバビリティシグナルと一緒に送信する必要がある情報と、後から結合できる情報を決める柔軟性を提供したいと考えています。これを私たちは「テレスコーピングされた識別情報」と呼びます。ユーザーは、ワイヤー上でOpenTelemetryのリソースのサイズをどれだけ小さく、あるいは大きくするかを決められます(それに対応して、ストレージソリューションによっては、保存時のデータポイントの大きさも変わります)。

例えば極端な場合、OpenTelemetryはテレメトリーを生成するすべてのシステムに対してUUIDを合成できます。ResourceとEntityのすべての識別属性は、このUUIDとの既知の関係を持つ、サイドチャネルを介して送信できます。これは実行時のテレメトリーの生成と送信を最適化しますが、その代償として、下流のストレージシステムは、取り込み時またはクエリ時にデータを結合し直す必要があります。アラートのような高パフォーマンスを要する用途では、この結合はコストが高くなる可能性があります。

実際には、ユーザーはSDKとCollector内のリソース検出の設定によって、Resourceの識別情報を制御します。最小限の識別情報を求めるユーザーは、リソース検出をservice.instance.idだけに限定するかもしれません。ユーザーの中には、多くの概念を追加してリソース検出を高度にカスタマイズする場合もあります。

OpenTelemetryは、大半のユーザーに適切な非正規化のトレードオフをもたらす、良好な「そのまま使える」リソース検出の集合を提供すべきですが、ユーザーが自身の必要に応じてシステムを微調整できるようにするべきです。