# 帳票設計書 1-Health Report

## 概要

本ドキュメントは、OpenSearchの `_cat/health` APIが出力するHealth Reportの帳票設計書である。クラスタ全体のヘルス状態をテキストテーブル形式で出力するCat APIエンドポイントの仕様を定義する。

### 本帳票の処理概要

Health Reportは、OpenSearchクラスタの健全性を即座に確認するための帳票である。クラスタのステータス（green/yellow/red）、ノード数、シャード数などの主要指標を1行のテキストテーブルとして出力する。

**業務上の目的・背景**：クラスタの運用監視において、クラスタ全体の健全性を一目で把握する必要がある。green/yellow/redのステータスに加え、ノード数やシャードの割り当て状況を即座に確認することで、障害の早期検知や運用判断の迅速化を実現する。

**帳票の利用シーン**：クラスタの定期監視、障害発生時の初期診断、デプロイ後のヘルスチェック、自動監視スクリプトでの状態取得に利用される。

**主要な出力内容**：
1. クラスタ名とヘルスステータス（green/yellow/red）
2. 総ノード数およびデータノード数
3. クラスタマネージャの検出状態
4. シャード統計（総数、プライマリ、リロケーティング、初期化中、未割り当て）
5. 保留中タスク数、最大タスク待機時間、アクティブシャード割合

**帳票の出力タイミング**：ユーザーが `GET /_cat/health` エンドポイントにHTTPリクエストを送信した時点で即座に出力される。

**帳票の利用者**：クラスタ管理者、SRE（Site Reliability Engineer）、監視システム、運用自動化スクリプト。

## 帳票種別

一覧表（テキストテーブル形式のクラスタヘルス情報）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| 151 | Cat ヘルス | `GET /_cat/health` | HTTP GETリクエスト |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（text/plain）/ JSON（application/json） |
| 用紙サイズ | N/A（REST APIレスポンス） |
| 向き | N/A |
| ファイル名 | N/A（HTTPレスポンスボディとして返却） |
| 出力方法 | HTTPレスポンス |
| 文字コード | UTF-8 |

### テキストテーブル固有設定

| 項目 | 内容 |
|-----|------|
| カラム区切り | スペース（text形式）/ JSON（format=json時） |
| ヘッダー表示 | `v` パラメータでヘッダー行を表示制御 |
| タイムスタンプ | `ts` パラメータでタイムスタンプ列の表示制御（デフォルト有効） |
| ソート | `s` パラメータで任意カラムによるソートが可能 |
| カラム選択 | `h` パラメータで表示カラムを選択可能 |

## 帳票レイアウト

### レイアウト概要

1行のテキストテーブルとしてクラスタのヘルス情報を出力する。タイムスタンプ付きヘッダーが先頭に付与される。

```
┌─────────────────────────────────────────────────────┐
│ epoch  timestamp  cluster  status  node.total  ...  │
├─────────────────────────────────────────────────────┤
│ 1706..  10:30:00  my-cl..  green   3           ...  │
└─────────────────────────────────────────────────────┘
```

### ヘッダー部（タイムスタンプヘッダー）

`startHeadersWithTimestamp()` メソッドにより、以下のタイムスタンプカラムが自動的に先頭に追加される。

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | epoch | UNIXエポック秒 | システム時刻 | 数値 |
| 2 | timestamp | 時刻文字列 | システム時刻 | HH:mm:ss |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | エイリアス |
|----|-------|------|-------------|---------|----------|
| 1 | cluster | クラスタ名 | ClusterHealthResponse.getClusterName() | 文字列 | cl |
| 2 | status | ヘルスステータス | ClusterHealthResponse.getStatus() | 小文字文字列（green/yellow/red） | st |
| 3 | node.total | 総ノード数 | ClusterHealthResponse.getNumberOfNodes() | 右寄せ数値 | nt, nodeTotal |
| 4 | node.data | データノード数 | ClusterHealthResponse.getNumberOfDataNodes() | 右寄せ数値 | nd, nodeData |
| 5 | discovered_cluster_manager | クラスタマネージャ検出状態 | ClusterHealthResponse.hasDiscoveredClusterManager() | 右寄せ真偽値 | dcm, dm |
| 6 | shards | 総シャード数 | ClusterHealthResponse.getActiveShards() | 右寄せ数値 | t, sh |
| 7 | pri | プライマリシャード数 | ClusterHealthResponse.getActivePrimaryShards() | 右寄せ数値 | p |
| 8 | relo | リロケーティング数 | ClusterHealthResponse.getRelocatingShards() | 右寄せ数値 | r |
| 9 | init | 初期化中シャード数 | ClusterHealthResponse.getInitializingShards() | 右寄せ数値 | i |
| 10 | unassign | 未割り当てシャード数 | ClusterHealthResponse.getUnassignedShards() | 右寄せ数値 | u |
| 11 | pending_tasks | 保留中タスク数 | ClusterHealthResponse.getNumberOfPendingTasks() | 右寄せ数値 | pt |
| 12 | max_task_wait_time | 最長タスク待機時間 | ClusterHealthResponse.getTaskMaxWaitingTime() | 時間値（0msの場合「-」） | mtwt |
| 13 | active_shards_percent | アクティブシャード割合 | ClusterHealthResponse.getActiveShardsPercent() | パーセンテージ（例: 100.0%） | asp |

### フッター部

フッター部は存在しない。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| なし | クラスタ全体のヘルス情報を常に1行出力 | - |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | `s` パラメータで任意指定可能 | 任意 |

### 改ページ条件

改ページは発生しない（常に1行の出力）。

## データベース参照仕様

### 参照テーブル一覧

本帳票はRDBを参照せず、OpenSearch内部のクラスタ状態情報を参照する。

| データソース | 用途 | 取得方法 |
|-----------|------|---------|
| ClusterHealthResponse | クラスタヘルス情報 | ClusterHealthRequest を NodeClient 経由で実行 |

### データソース別参照項目詳細

#### ClusterHealthResponse

| 参照項目（メソッド名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| getClusterName() | cluster | 無条件 | - |
| getStatus() | status | 無条件 | toLowerCase(Locale.ROOT) で小文字化 |
| getNumberOfNodes() | node.total | 無条件 | - |
| getNumberOfDataNodes() | node.data | 無条件 | - |
| hasDiscoveredClusterManager() | discovered_cluster_manager | 無条件 | - |
| getActiveShards() | shards | 無条件 | - |
| getActivePrimaryShards() | pri | 無条件 | - |
| getRelocatingShards() | relo | 無条件 | - |
| getInitializingShards() | init | 無条件 | - |
| getUnassignedShards() | unassign | 無条件 | - |
| getNumberOfPendingTasks() | pending_tasks | 無条件 | - |
| getTaskMaxWaitingTime() | max_task_wait_time | 無条件 | 0msの場合「-」を表示 |
| getActiveShardsPercent() | active_shards_percent | 無条件 | `%1.1f%%` フォーマットで表示 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| active_shards_percent | ClusterHealthResponse.getActiveShardsPercent() | 小数点第1位 | `String.format(Locale.ROOT, "%1.1f%%", value)` |
| max_task_wait_time | getTaskMaxWaitingTime().millis() == 0 ? "-" : value | なし | 0msの場合はハイフン表示 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[GET /_cat/health リクエスト受信] --> B[AbstractCatAction.prepareRequest]
    B --> C{helpパラメータ?}
    C -->|Yes| D[ヘルプテキスト出力]
    C -->|No| E[RestHealthAction.doCatRequest]
    E --> F[ClusterHealthRequest 生成]
    F --> G[NodeClient.admin.cluster.health 実行]
    G --> H[ClusterHealthResponse 受信]
    H --> I[buildTable でテーブル構築]
    I --> J[RestTable.buildResponse でレスポンス生成]
    J --> K[HTTPレスポンス返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| クラスタ接続失敗 | NodeClientがクラスタに接続できない場合 | 接続エラーメッセージ | クラスタの状態を確認 |
| タイムアウト | timeoutパラメータ超過 | タイムアウトエラー | timeout値の調整またはクラスタ負荷の確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 常に1行 |
| 目標出力時間 | ミリ秒単位（クラスタヘルスの内部API呼び出し） |
| 同時出力数上限 | 制限なし（HTTPリクエスト並行度に依存） |

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

- `allowSystemIndexAccessByDefault()` が `true` に設定されており、システムインデックスへのアクセスがデフォルトで許可されている。
- セキュリティプラグイン導入時は、`cluster:monitor/health` アクションの権限が必要。

## 備考

- `discovered_cluster_manager` ヘッダーには後方互換性のため `discovered_master` エイリアスが残されている（将来のバージョンで削除予定）。
- `ts=false` パラメータを指定するとタイムスタンプカラム（epoch, timestamp）を非表示にできる。

---

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

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

### 推奨読解順序

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

まず、帳票の出力データの元となるレスポンスオブジェクトとテーブル構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Table.java | `server/src/main/java/org/opensearch/common/Table.java` | テキストテーブルのデータ構造。startHeaders/addCell/startRow/endRow のAPIを理解する |
| 1-2 | ClusterHealthResponse.java | `server/src/main/java/org/opensearch/action/admin/cluster/health/ClusterHealthResponse.java` | ヘルス情報のレスポンスオブジェクト。各getter メソッドが帳票項目に対応する |

**読解のコツ**: Table クラスはCat API共通のテーブル構造。`addCell` の第2引数の文字列でエイリアスや表示設定が定義される。

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

処理の起点となるRestアクションクラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractCatAction.java | `server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java` | Cat API共通の基底クラス。`prepareRequest` メソッド（行68）で help パラメータ判定後に `doCatRequest` を呼び出す |
| 2-2 | RestHealthAction.java | `server/src/main/java/org/opensearch/rest/action/cat/RestHealthAction.java` | Health Report のメインクラス |

**主要処理フロー**:
1. **行57-59**: `routes()` で `GET /_cat/health` をルーティング登録
2. **行77-86**: `doCatRequest()` で ClusterHealthRequest を生成し、非同期でクラスタヘルス取得
3. **行89-113**: `getTableWithHeader()` でテーブルヘッダーを定義（13カラム + タイムスタンプ）
4. **行115-133**: `buildTable()` でレスポンスデータからテーブル行を構築

#### Step 3: レスポンス変換層を理解する

テーブルデータからHTTPレスポンスへの変換を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | RestTable.java | `server/src/main/java/org/opensearch/rest/action/cat/RestTable.java` | テーブルからtext/json形式のレスポンスを生成する共通ユーティリティ |

**主要処理フロー**:
- **buildResponse()**: format パラメータに応じてテキストまたはJSON形式でレスポンスを構築

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

```
AbstractCatAction.prepareRequest() [行68]
    |
    +-- RestHealthAction.doCatRequest() [行77]
           |
           +-- ClusterHealthRequest 生成 [行78]
           |
           +-- NodeClient.admin().cluster().health() [行80]
                  |
                  +-- RestResponseListener.buildResponse() [行82]
                         |
                         +-- RestHealthAction.buildTable() [行115]
                         |      |
                         |      +-- getTableWithHeader() [行89]
                         |      +-- ClusterHealthResponse のgetter呼び出し [行118-131]
                         |
                         +-- RestTable.buildResponse() [行83]
```

### データフロー図

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

GET /_cat/health  --->  RestHealthAction            --->  テキストテーブル
                           |                               (text/plain)
                           v                               or JSON
                  ClusterHealthRequest
                           |
                           v
                  ClusterHealthResponse
                     (内部API応答)
                           |
                           v
                  Table オブジェクト構築
                           |
                           v
                  RestTable.buildResponse
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RestHealthAction.java | `server/src/main/java/org/opensearch/rest/action/cat/RestHealthAction.java` | ソース | Health Report のメイン処理クラス |
| AbstractCatAction.java | `server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java` | ソース | Cat API共通基底クラス |
| RestTable.java | `server/src/main/java/org/opensearch/rest/action/cat/RestTable.java` | ソース | テーブル→レスポンス変換ユーティリティ |
| Table.java | `server/src/main/java/org/opensearch/common/Table.java` | ソース | テーブルデータ構造 |
| ClusterHealthRequest.java | `server/src/main/java/org/opensearch/action/admin/cluster/health/ClusterHealthRequest.java` | ソース | クラスタヘルスリクエスト |
| ClusterHealthResponse.java | `server/src/main/java/org/opensearch/action/admin/cluster/health/ClusterHealthResponse.java` | ソース | クラスタヘルスレスポンス |
| ActionModule.java | `server/src/main/java/org/opensearch/action/ActionModule.java` | ソース | RestHealthAction のルーティング登録 |
