# ログのデータモデル

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/logs/data-model/


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

これは、アプリケーションのログファイル、マシンが生成するイベント、システムログなど、さまざまな発生源のログを表現できるデータモデルとセマンティック規約です。既存のログフォーマットは、このデータモデルへ一意にマッピングできます。対象のログフォーマットが同等の能力を持つ限り、このデータモデルからの逆マッピングも可能です。

このデータモデルの目的は、ログレコードとは何か、ロギングシステムによって記録・転送・保存・解釈される必要があるデータは何かについて、共通の理解を持つことです。

この提案は、[Standalone Log](../../glossary/#standalone-log)のデータモデルを定義します。

## 設計上の注記

### 要件

このデータモデルは、次の要件を満たすように設計されました。

- 既存のログフォーマットをこのデータモデルへ一意にマッピングできるべきです。任意のログフォーマットのログデータをこのデータモデルへ変換し、再び元に戻す変換は、理想的には同一のデータになるべきです。

- 他のログフォーマットからこのデータモデルへのマッピングは、意味的に妥当であるべきです。このデータモデルは、既存のログフォーマットの特定の要素の意味を保持しなければなりません。

- 任意のログフォーマットAのログデータをこのデータモデルへ変換し、続いてこのデータモデルから別のログフォーマットBへ変換する処理は、理想的には、ログフォーマットAからログフォーマットBへの妥当な直接変換と比べて劣らない、意味のあるログデータの変換にならなければなりません。

- データの保存や送信を必要とする具体的な実装において、このデータモデルを効率的に表現できるべきです。ここで主に問題にしているのは効率性の2つの側面です。シリアライズ・デシリアライズに要するCPU使用量と、シリアライズされた形式に必要な容量です。これは、データモデル自体よりもデータモデルの具体的な表現形式によって影響される間接的な要件ですが、念頭に置いておく価値があります。

このデータモデルは、次の3種類のログとイベントをうまく表現することを目指しています。

- **システムフォーマット**。オペレーティングシステムが生成するログとイベントであり、私たちにはそのフォーマットを変更したり含まれる情報に影響を与える手段がありません（変更可能なアプリケーションがそのデータを生成している場合を除きます）。システムフォーマットの例はSyslogです。

- **サードパーティアプリケーション**。サードパーティのアプリケーションが生成するログとイベントです。フォーマットのカスタマイズなど、含まれる情報について一定の制御が可能な場合があります。例はApacheのログファイルです。

- **ファーストパーティアプリケーション**。私たち自身が開発し、ログとイベントの生成方法やログに含める情報について一定の制御を持つアプリケーションです。必要であれば、アプリケーションのソースコードを変更できる可能性があります。

### Events

Eventは、LogRecordに対するOpenTelemetryの標準化されたフォーマットです。ログ向けに定義されたすべてのセマンティック規約は、Eventとしてフォーマットされるべきです（SHOULD）。Eventフォーマットの要件と詳細は、[セマンティック規約](/works/otel-specs-ja/semconv/general/events/)にあります。

Eventは、OpenTelemetryの計装によって使われることを意図しています。すべてのLogRecordがEventとしてフォーマットされることは要件ではありません。

### フィールドの種別

このデータモデルは、ログレコードの物理的なフォーマットやエンコーディングとは無関係に、ログレコードの論理モデルを定義します。各レコードには、次の2種類のフィールドが含まれます。

- 特定の型と意味を持つ、名前付きのトップレベルフィールド。

- [Attribute Collection](../../common/#attribute-collections)として格納されるフィールド。その値は[AnyValue](../../common/#anyvalue)です。よく知られたフィールドのキーと値は、そのフィールドを扱うすべての関係者が同じ解釈を持てるように、キー名と可能な値についてのセマンティック規約に従います。`Resource`フィールドと`Attributes`フィールドのセマンティック規約への参照や例については、[付録A](../data-model-appendix/#appendix-a-example-mappings)を参照してください。

これら2種類のフィールドを持つ理由は次のとおりです。

- ほぼ常に存在する名前付きトップレベルフィールドを効率的に表現できること（例えば、Protocol Buffersのように、フィールドが列挙されるが配線上で名前を持たないエンコーディングを使う場合）。

- 名前付きフィールドの型を強制できること。これは、型チェックを行うコンパイル言語にとって非常に有用です。

- 頻度の低いデータをAttribute Collectionで表現できる柔軟性。これには、標準化された意味を持つよく知られたデータと、アプリケーションがログに含めたい任意のカスタムデータの両方が含まれます。

このデータモデルを設計する際、トップレベルの名前付きフィールドをいつ使うべきかについて、次の考え方に従いました。

- そのフィールドが、すべてのレコードで必須であるか、よく知られたログ・イベントフォーマットで頻繁に存在する（`Timestamp`など）か、今後のロギングシステムのログレコードで頻繁に存在すると見込まれる（`TraceId`など）必要があります。

- そのフィールドの意味は、既知のすべてのログ・イベントフォーマットで同一であり、このデータモデルへ直接かつ一意にマッピングできなければなりません。

上記の両方の条件を満たすフィールドにのみ、レコードのトップレベル構造の中に場所を与えました。

## Log and Event Record Definition

[付録A](../data-model-appendix/#appendix-a-example-mappings)には、既存のログフォーマットが以下で定義するフィールドへどのようにマッピングされるかを示す多数の例があります。フィールドの意味について疑問がある場合は、これらの例を確認すると役立つことがあります。

ログレコードのフィールドの一覧は次のとおりです。

| フィールド名 | 説明 |
| ---------- | ----------- |
| Timestamp | イベントが発生した時刻。 |
| ObservedTimestamp | イベントが観測された時刻。 |
| TraceId | リクエストのトレースID。 |
| SpanId | リクエストのスパンID。 |
| TraceFlags | W3Cのトレースフラグ。 |
| SeverityText | 重大度テキスト（ログレベルとも呼ばれる）。 |
| SeverityNumber | 重大度の数値。 |
| Body | ログレコードのbody。 |
| Resource | ログを生成した観測対象エンティティの記述。 |
| InstrumentationScope | ログを発行したスコープの記述。 |
| Attributes | イベントに関する追加情報。 |
| EventName | イベントのクラス・種別を識別する名前。 |

以下は各フィールドの詳細な説明です。

### Field: `Timestamp`

型: Timestamp（UNIXエポックからのuint64ナノ秒）。

説明: イベント発生元のクロックで計測された、イベントが発生した時刻（すなわち発生元での時刻）。このフィールドはオプションであり、発生元のタイムスタンプが不明な場合は欠落することがあります。

### Field: `ObservedTimestamp`

型: Timestamp（UNIXエポックからのuint64ナノ秒）。

説明: 収集システムによってイベントが観測された時刻。OpenTelemetry内で発生するイベント（例えばOpenTelemetry Logging SDKを使う場合）では、このタイムスタンプは通常生成時に設定され、Timestampと等しくなります。外部で発生し、OpenTelemetryによって収集されるイベント（例えばCollectorを使う場合）では、これはOpenTelemetryのコードのクロックで計測された、OpenTelemetryのコードがそのイベントを観測した時刻です。このフィールドは、OpenTelemetryによってイベントが観測された時点で設定されるべきです（SHOULD）。

OpenTelemetryのログデータを、タイムスタンプを1つしかサポートしないフォーマットへ変換する場合、あるいは内部でタイムスタンプを1つしかサポートしない受信者がOpenTelemetryのログデータを受信する場合は、次のロジックが推奨されます。

- `Timestamp`が存在する場合はそれを使い、そうでない場合は`ObservedTimestamp`を使います。

### Trace Context Fields

#### Field: `TraceId`

型: バイト列。

説明: [W3C Trace Context](https://www.w3.org/TR/trace-context/#trace-id)で定義されているリクエストのトレースID。リクエスト処理の一部であり、割り当てられたトレースIDを持つログに設定できます。このフィールドはオプションです。

#### Field: `SpanId`

型: バイト列。

説明: スパンID。特定の処理スパンの一部であるログに設定できます。SpanIdが存在する場合、TraceIdも存在するべきです（SHOULD）。このフィールドはオプションです。

#### Field: `TraceFlags`

型: バイト。

説明: [W3C Trace Context](https://www.w3.org/TR/trace-context/#trace-flags)仕様で定義されているトレースフラグ。本稿執筆時点では、この仕様はSAMPLEDフラグ1つのみを定義しています。このフィールドはオプションです。

### 重大度に関するフィールド

#### Field: `SeverityText`

型: string。

説明: 重大度テキスト（ログレベルとも呼ばれる）。これは、発生元で知られている重大度の元の文字列表現です。このフィールドが欠落しており、`SeverityNumber`が存在する場合、`SeverityNumber`に対応する短縮名を代わりに使ってよい（MAY）。このフィールドはオプションです。

#### Field: `SeverityNumber`

型: number。

説明: 本文書で説明されている値に正規化された、重大度の数値。このフィールドはオプションです。

`SeverityNumber`は整数です。数値が小さいほど重大度が低いイベント（デバッグイベントなど）に対応し、数値が大きいほど重大度が高いイベント（エラーやクリティカルなイベントなど）に対応します。

例えば、`SeverityNumber=17`は、`SeverityNumber=20`のエラーよりも重大度が低いエラーを表します。

次の表は、`SeverityNumber`の値の意味を定義します。

| SeverityNumberの範囲 | 範囲名 | 意味 |
| -------------------- | ---------- | --------------------------------------------------------------------------------------- |
| 1-4                  | TRACE      | きめ細かなデバッグイベント。既定の設定では通常無効化されています。 |
| 5-8                  | DEBUG      | デバッグイベント。 |
| 9-12                 | INFO       | 情報イベント。何らかのイベントが発生したことを示します。 |
| 13-16                | WARN       | 警告イベント。エラーではありませんが、情報イベントよりも重要である可能性が高いものです。 |
| 17-20                | ERROR      | エラーイベント。何らかの問題が発生したことを示します。 |
| 21-24                | FATAL      | アプリケーションやシステムのクラッシュなどの致命的なエラー。 |

`SeverityNumber=0`は、値が未指定であることを表すために使ってよい（MAY）。

#### `SeverityNumber`のマッピング

既存のロギングシステムやフォーマット（以下、**発生元フォーマット**）からのマッピングでは、上の表で各範囲に与えられた意味に基づき、そのフォーマット固有の重大度（ログレベル）がこのデータモデルの`SeverityNumber`のどれに対応するかを定義しなければなりません。

発生元フォーマットに、この表の単一の範囲に一致する重大度が複数ある場合、発生元フォーマットの重大度には、発生元の重大度がどの程度重大（重要）であるかに応じて、その範囲内の数値を割り当てなければなりません。

例えば、発生元フォーマットがエラーイベントとして「Error」と「Critical」を定義しており、「Critical」の方がより重要でより重大な状況を表すのであれば、次のように`SeverityNumber`の値をマッピングできます。「Error」→17、「Critical」→18。

発生元フォーマットに、その範囲の意味に一致する重大度が1つしかない場合は、その重大度にはその範囲の最小値を割り当てることが推奨されます。

例えば、発生元フォーマットに「Informational」というログレベルがあり、類似の意味を持つ他のログレベルがない場合は、「Informational」に`SeverityNumber=9`を使うことが推奨されます。

重大度やログレベルの概念を定義していない発生元フォーマットは、`SeverityNumber`と`SeverityText`フィールドを省略してよい（MAY）。バックエンドやUIは、重大度情報が欠落しているログレコードを区別して表現してもよく、`SeverityNumber`と`SeverityText`フィールドが欠落しているログレコードを、`SeverityNumber`がINFO（数値9）に等しく設定されているものとして解釈してもかまいません。

#### 逆マッピング

`SeverityNumber`から特定のフォーマットへの逆マッピングを行う際、そのフォーマットに対応するマッピングエントリが`SeverityNumber`にない場合は、同じ重大度範囲内で数値的に最も近い対象の重大度を選ぶことが推奨されます。

例えばZapには、INFO範囲の重大度が「Info」という名前で1つしかありません。逆マッピングを行う際、INFO範囲（数値9-12）のすべての`SeverityNumber`の値はZapの「Info」レベルにマッピングされます。

#### エラーのセマンティクス

`SeverityNumber`が存在し、その値がERROR（数値17）以上である場合、そのログレコードが誤りのある状況を表していることを示します。この事実をどのように使うかは、この値の読み手が判断します（例えばUIは、こうしたエラーを異なる色で表示したり、誤りのあるすべてのログレコードを検索する機能を持たせたりできます）。

ログレコードが誤りのあるイベントを表しており、発生元フォーマットに重大度やログレベルの概念が定義されていない場合は、マッピングの過程で`SeverityNumber`をERROR（数値17）に設定することが推奨されます。ログレコードが誤りのないイベントを表す場合、`SeverityNumber`フィールドは省略してもよく、ERROR（数値17）未満の任意の数値に設定してもかまいません。この場合の推奨値はINFO（数値9）です。他のマッピング例については[付録B](../data-model-appendix/#appendix-b-severitynumber-example-mappings)を参照してください。

#### 重大度の表示

次の表は、各`SeverityNumber`値に対する推奨の短縮名を定義します。この短縮名は、例えばUIで`SeverityNumber`を表現する際に使えます。

| SeverityNumber | 短縮名 |
| -------------- | ---------- |
| 1              | TRACE      |
| 2              | TRACE2     |
| 3              | TRACE3     |
| 4              | TRACE4     |
| 5              | DEBUG      |
| 6              | DEBUG2     |
| 7              | DEBUG3     |
| 8              | DEBUG4     |
| 9              | INFO       |
| 10             | INFO2      |
| 11             | INFO3      |
| 12             | INFO4      |
| 13             | WARN       |
| 14             | WARN2      |
| 15             | WARN3      |
| 16             | WARN4      |
| 17             | ERROR      |
| 18             | ERROR2     |
| 19             | ERROR3     |
| 20             | ERROR4     |
| 21             | FATAL      |
| 22             | FATAL2     |
| 23             | FATAL3     |
| 24             | FATAL4     |

個々のログレコードを表示する際は、`SeverityText`と`SeverityNumber`の両方の値を表示することが推奨されます。この場合、推奨される結合文字列は、短縮名の後に括弧書きで`SeverityText`を続ける形です。

例えば「Informational」というSyslogレコードは、**INFO (Informational)**として表示されます。特定のログレコードで`SeverityNumber`は定義されているが`SeverityText`が欠落している場合は、短縮名のみを表示することが推奨されます（例えば**INFO**）。

重大度を表現するためにドロップダウンリスト（または可能な値の集合を表すことを意図した他のUI要素）を使う場合は、そうしたUI要素には短縮名を表示することが望まれます。

例えば、重大度によってログレコードをフィルタリングできる重大度のドロップダウンリストは、システムに知られているすべての個別の`SeverityText`値（要素数が多くなりがちで、しばしば大文字小文字や省略の違いしかない、例えば「Info」対「Information」）を列挙するドロップダウンリストと比べて、`SeverityNumber`の短縮名（そのため要素数の上限が限られる）を含めた方が、使いやすくなる可能性が高いです。

#### 重大度の比較

重大度が未満・以上の比較に関わる文脈では、`SeverityNumber`フィールドを使うべきです。`SeverityNumber=0`が未指定の重大度を表すために使われている場合には、特別な扱いを与えてもよい（MAY）。

### Field: `Body`

型: [AnyValue](../../common/#anyvalue)。

説明: ログレコードのbodyを含む値。例えば、イベントを自由形式で記述する人間が読める文字列メッセージ（複数行を含む）であることも、他の値の配列やマップから構成される構造化データであることもあります。Bodyは、アプリケーションが発行する構造化ログの意味を保持するため、[AnyValue](../../common/#anyvalue)をサポートしなければなりません（MUST）。同じ発生元から来るイベントの発生ごとに変化することがあります。このフィールドはオプションです。

### Field: `Resource`

型: [Resource](/works/otel-specs-ja/spec/resource/sdk/)。

説明: ログの発生源、すなわち[リソース](/works/otel-specs-ja/spec/overview/#リソース)を記述します。同じイベント発生源から来るイベントが時間をおいて複数回発生しても、それらはすべて同じ`Resource`の値を持ちます。例えば、そのレコードを発行しているアプリケーションや、アプリケーションが動作しているインフラストラクチャに関する情報を含められます。このデータモデルを表現するデータフォーマットは、同じ発生源から来るログレコードのバッチごとに`Resource`フィールドを1回だけ記録できるように設計してもかまいません。OpenTelemetryの[リソースに関するセマンティック規約](https://opentelemetry.io/docs/specs/semconv/resource/)に従うべきです（SHOULD）。このフィールドはオプションです。

### Field: `InstrumentationScope`

型: [Instrumentation Scope](/works/otel-specs-ja/spec/common/instrumentation-scope/)。

説明: [計装スコープ](/works/otel-specs-ja/spec/common/instrumentation-scope/)。同じスコープから来るイベントが時間をおいて複数回発生しても、それらはすべて同じ`InstrumentationScope`の値を持ちます。このフィールドはオプションです。

### Field: `Attributes`

型: [Attribute Collection](../../common/#attribute-collections)。

説明: 特定のイベント発生に関する追加情報。特定の発生源に対して固定されている`Resource`フィールドとは異なり、`Attributes`は同じ発生源から来るイベントの発生ごとに変化することがあります。（[Trace Context Fields](#trace-context-fields)以外の）リクエストコンテキストに関する情報を含められます。このフィールドはオプションです。

#### エラーとエクセプション

ログレコードに関連付けられたエラーやエクセプションに関する追加情報は、レコードの`Attributes`セクションの構造化データに含めてよい（MAY）。含める場合は、OpenTelemetryの[エクセプション関連属性のセマンティック規約](/works/otel-specs-ja/semconv/exceptions/exceptions-logs/)に従わなければなりません（MUST）。

### Field: `EventName`

型: string。

説明: [Event](#events)のクラス・種別を識別する名前。この名前は、（属性とbodyの両方を含む）イベントの構造を一意に識別すべきです（SHOULD）。空でないイベント名を持つログレコードは[Event](#events)です。

## ログレコードの例

ログレコードの例については、[JSON File serialization](/works/otel-specs-ja/spec/protocol/file-exporter/#例)を参照してください。

## マッピングの例

ログフォーマットのマッピング例については、[データモデル付録](../data-model-appendix/)を参照してください。

## 参考文献

- ログのデータモデル [OTEP 0097](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.60.0/oteps/logs/0097-log-data-model.md)

