# 通知設計書 28-SparkListenerLogStart

## 概要

本ドキュメントは、Apache SparkにおけるSparkListenerLogStartイベント通知の設計仕様を定義する。このイベントは、イベントログのメタデータを記録するために使用され、イベントログファイルの先頭にSparkバージョン情報を書き込む。

### 本通知の処理概要

本通知は、EventLoggingListenerの初期化時にイベントログファイルの先頭にメタデータとして書き込まれるイベントである。ライブアプリケーション中にLiveListenerBusを経由して配信されることはなく、イベントログファイルに直接書き込まれた後、履歴サーバでのログ再生時にリスナーに配信される。

**業務上の目的・背景**：イベントログファイルのフォーマットバージョンを特定するために必要なメタデータである。Sparkのバージョンが異なると、イベントのJSON形式が変更される可能性があるため、ログを正しく解析するためにバージョン情報が不可欠である。FsHistoryProviderがログを読み込む際に、このイベントからSparkバージョンを抽出してアプリケーション情報に記録する。

**通知の送信タイミング**：EventLoggingListenerのstart()メソッド内のinitEventLog()で、イベントログファイルの最初のエントリとして書き込まれる。LiveListenerBusを経由した通知ではない。

**通知の受信者**：履歴サーバでのログ再生時に、AppStatusListener（sparkVersionの設定）とFsHistoryProviderのAppListingListener（appSparkVersionの設定）がonOtherEventメソッド経由で受信する。本イベントはSparkListenerBusのdoPostEventに専用のcaseブランチを持たず、onOtherEventにフォールスルーする。

**通知内容の概要**：sparkVersion（Sparkバージョン文字列）の1フィールドのみを含む。

**期待されるアクション**：履歴サーバがアプリケーションのSparkバージョンを正確に記録し、バージョン互換性のあるログ解析を可能にする。

## 通知種別

アプリ内イベント通知（イベントログファイルへの直接書き込み / 履歴サーバでのログ再生時にonOtherEvent経由で配信）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | イベントログファイルへの直接書き込み（LiveListenerBus経由ではない） |
| 優先度 | 高（イベントログのメタデータ） |
| リトライ | 無 |

### 送信先決定ロジック

本イベントはLiveListenerBusを経由せず、EventLoggingListenerがinitEventLog()内でJsonProtocol.sparkEventToJsonStringを使用してJSON文字列に変換し、logWriter.writeEventで直接ファイルに書き込む。履歴サーバでのログ再生時には、SparkListenerBus.doPostEventのdefault caseによりlistener.onOtherEvent()が呼び出される。

## 通知テンプレート

### メール通知の場合

該当なし。本通知はSparkの内部イベントログへの書き込みおよびログ再生時の処理である。

### 本文テンプレート

```
イベント: SparkListenerLogStart
Spark Version: {sparkVersion}
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| sparkVersion | Sparkバージョン文字列 | SPARK_VERSION定数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| イベントログ初期化 | EventLoggingListener.start() | spark.eventLog.enabled=true | initEventLog()内でイベントログファイルの最初のエントリとして書き込み |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| spark.eventLog.enabled=false | イベントログが無効な場合、EventLoggingListenerが生成されないため本イベントも書き込まれない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[EventLoggingListener.start] --> B[initEventLog]
    B --> C[SparkListenerLogStart SPARK_VERSION 生成]
    C --> D[JsonProtocol.sparkEventToJsonString]
    D --> E[logWriter.writeEvent flushLogger=true]
    E --> F[イベントログファイルに書き込み]
    F --> G[履歴サーバでのログ再生時]
    G --> H[SparkListenerBus.doPostEvent: default case]
    H --> I[listener.onOtherEvent]
    I --> J[AppStatusListener: sparkVersion設定]
    I --> K[FsHistoryProvider: appSparkVersion設定]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし。

### 更新テーブル一覧

該当なし。AppStatusListenerではsparkVersionというインスタンス変数が更新されるのみ。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ログ書き込み失敗 | イベントログファイルへの書き込みエラー | EventLoggingListenerが例外をスロー |
| JSON変換失敗 | JsonProtocol.sparkEventToJsonStringの変換エラー | 例外がスロー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | N/A（イベントログ初期化時に1回のみ書き込み） |
| 1日あたり上限 | N/A |

### 配信時間帯

制限なし。EventLoggingListenerの初期化時に1回のみ書き込まれる。

## セキュリティ考慮事項

本通知にはSparkバージョン文字列のみが含まれ、個人情報や機密データは含まれない。

## 備考

- 本イベントはSparkListenerEvent.logEventメソッドをオーバーライドしておらず、デフォルトでtrueを返す。
- SparkListenerBus.doPostEventには専用のcaseブランチが存在せず、default case（行100: `case _ => listener.onOtherEvent(event)`）にフォールスルーする。
- FsHistoryProviderではLOG_START_EVENT_PREFIX（行1510: `"{\"Event\":\"SparkListenerLogStart\""`）による高速文字列マッチングが行われる。
- JsonProtocolのlogStartToJson（行362-366）では"Spark Version"キーでバージョン文字列をJSON出力する。ただし、書き込み時は常にSPARK_VERSION定数が使用される（行365）。
- AppStatusListenerのonOtherEvent内（行111）で`case SparkListenerLogStart(version) => sparkVersion = version`として処理される。

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SparkListener.scala | `core/src/main/scala/org/apache/spark/scheduler/SparkListener.scala` | 行287-291: SparkListenerLogStartケースクラスの定義。sparkVersionの1フィールドのみ。「An internal class that describes the metadata of an event log.」とコメントあり |

**読解のコツ**: @DeveloperApiアノテーションが付与されているが、コメントで内部クラスであることが明記されている。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EventLoggingListener.scala | `core/src/main/scala/org/apache/spark/scheduler/EventLoggingListener.scala` | 行82-93: start()メソッドとinitEventLog()メソッド。イベントログの最初のエントリとしてSparkListenerLogStartを書き込む |

**主要処理フロー**:
1. **行82-84**: start()メソッド - logWriter.start()の後にinitEventLog()を呼び出し
2. **行87-93**: initEventLog() - SparkListenerLogStart(SPARK_VERSION)を生成し、JsonProtocolでJSON変換後にlogWriter.writeEventで書き込み

#### Step 3: リスナー処理を理解する（履歴サーバ）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AppStatusListener.scala | `core/src/main/scala/org/apache/spark/status/AppStatusListener.scala` | 行110-111: onOtherEvent内でSparkListenerLogStartをパターンマッチし、sparkVersionを設定 |
| 3-2 | FsHistoryProvider.scala | `core/src/main/scala/org/apache/spark/deploy/history/FsHistoryProvider.scala` | 行1628-1631: onOtherEvent内でSparkListenerLogStartをパターンマッチし、attempt.appSparkVersionを設定 |

#### Step 4: JSON直列化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | JsonProtocol.scala | `core/src/main/scala/org/apache/spark/util/JsonProtocol.scala` | 行362-366: logStartToJsonメソッド。"Spark Version"キーでSPARK_VERSIONを出力 |
| 4-2 | JsonProtocol.scala | `core/src/main/scala/org/apache/spark/util/JsonProtocol.scala` | 行1155-1157: logStartFromJsonメソッド。JSONからオブジェクトへの逆変換 |

### プログラム呼び出し階層図

```
EventLoggingListener.start()
    |
    +-- logWriter.start()
    +-- initEventLog()
           |
           +-- SparkListenerLogStart(SPARK_VERSION)
           +-- JsonProtocol.sparkEventToJsonString(metadata)
           +-- logWriter.writeEvent(eventJson, flushLogger=true)

[履歴サーバ再生時]
FsHistoryProvider / ReplayListenerBus
    |
    +-- SparkListenerBus.doPostEvent
           |
           +-- case _ => listener.onOtherEvent(event)
                  |
                  +-- AppStatusListener.onOtherEvent
                  |      |
                  |      +-- case SparkListenerLogStart(version) => sparkVersion = version
                  |
                  +-- FsHistoryProvider.AppListingListener.onOtherEvent
                         |
                         +-- case SparkListenerLogStart(sparkVersion) => attempt.appSparkVersion = sparkVersion
```

### データフロー図

```
[入力]                          [処理]                              [出力]

SPARK_VERSION定数 ---------> EventLoggingListener.initEventLog -> イベントログファイル先頭
                                                                    (JSON形式)

[履歴サーバ再生時]
イベントログファイル --------> ReplayListenerBus.replay ----------> AppStatusListener.sparkVersion
                                                                    FsHistoryProvider.appSparkVersion
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SparkListener.scala | `core/src/main/scala/org/apache/spark/scheduler/SparkListener.scala` | ソース | イベントケースクラス定義 |
| SparkListenerBus.scala | `core/src/main/scala/org/apache/spark/scheduler/SparkListenerBus.scala` | ソース | イベント配信ディスパッチ（default caseでonOtherEvent） |
| EventLoggingListener.scala | `core/src/main/scala/org/apache/spark/scheduler/EventLoggingListener.scala` | ソース | イベント生成・書き込み元 |
| AppStatusListener.scala | `core/src/main/scala/org/apache/spark/status/AppStatusListener.scala` | ソース | sparkVersion設定リスナー |
| FsHistoryProvider.scala | `core/src/main/scala/org/apache/spark/deploy/history/FsHistoryProvider.scala` | ソース | 履歴サーバのバージョン情報管理 |
| JsonProtocol.scala | `core/src/main/scala/org/apache/spark/util/JsonProtocol.scala` | ソース | JSON直列化・逆直列化 |
