# 通知設計書 2-window/logMessage

## 概要

本ドキュメントは、serve-d LSPサーバーからクライアントへ送信される `window/logMessage` 通知の設計を記述する。この通知はLSP標準仕様に準拠し、クライアントのログ出力にメッセージを送信するために使用される。

### 本通知の処理概要

`window/logMessage` 通知は、serve-dサーバーがクライアント（エディタ）のログ出力チャネルにメッセージを送信するための通知である。RPCProcessor.log()メソッド経由で送信され、主にreportProgress()関数内で進捗情報のログ出力に使用されている。window/showMessageとは異なり、ユーザーに対してUIダイアログを表示するのではなく、クライアント側のOutput Channelやログパネルにメッセージを記録する。

**業務上の目的・背景**：LSPサーバーは内部処理の進捗状況やデバッグ情報をクライアント側のログに記録する必要がある。特にserve-dでは、ワークスペースの初期化進捗、DCD（D Completion Daemon）の起動状況、設定の読み込み状況などをクライアントのログ出力に送信し、ユーザーがトラブルシューティングを行えるようにしている。

**通知の送信タイミング**：reportProgress()関数が呼び出されるたびに送信される。具体的には、グローバルスタートアップ時、設定ロード時、ワークスペーススタートアップ時、補完サーバー起動時、dubリロード時、インポートリロード時、インポートアップグレード時に送信される。

**通知の受信者**：LSPクライアント（VSCode等のエディタ）が受信し、Output Channel（serve-dの出力パネル）にログとして表示する。

**通知内容の概要**：MessageType.log（値=4）とフォーマットされた進捗メッセージで構成される。メッセージには経過時間、進捗種別、ステップ数/最大数が含まれる。

**期待されるアクション**：通常は即座のアクションは不要だが、問題発生時にユーザーがログを確認してトラブルシューティングに利用する。

## 通知種別

LSP標準通知（サーバー -> クライアント）/ クライアントログ出力

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（JSON-RPC通知） |
| 優先度 | 低（ログ情報） |
| リトライ | 無し |

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

LSP接続中のクライアント（エディタ）に対して直接送信される。送信先の選択ロジックは存在しない。

## 通知テンプレート

### LSP通知の場合

| 項目 | 内容 |
|-----|------|
| メソッド名 | `window/logMessage` |
| パラメータ型 | `LogMessageParams` |
| 形式 | JSON-RPC 2.0 通知 |

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "method": "window/logMessage",
  "params": {
    "type": 4,
    "message": "[progress] [000.123] [globalStartup] 0 / 0: Initializing serve-d..."
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | メッセージ種別（常にMessageType.log=4） | RPCProcessor.log()のテンプレート引数 | Yes |
| message | ログメッセージ文字列 | text()関数による引数結合 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 進捗通知 | globalStartup | serve-d初回初期化時 | doGlobalStartup内のreportProgress |
| 進捗通知 | configLoad | ワークスペース設定ロード時 | changedConfig内のreportProgress |
| 進捗通知 | configFinish | 全設定ロード完了時 | configFinished内のreportProgress |
| 進捗通知 | workspaceStartup | ワークスペースルート初期化時 | doStartup内のreportProgress |
| 進捗通知 | completionStartup | 補完サーバー起動時 | doStartup内のreportProgress |
| 進捗通知 | dubReload | dub再読み込み時 | delayedProjectActivation内のreportProgress |
| 進捗通知 | importReload | インポートパス再読み込み時 | lazyStartDCDServer内のreportProgress |
| 進捗通知 | importUpgrades | 依存関係アップグレード時 | delayedProjectActivation内のreportProgress |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 特になし | reportProgress()が呼ばれるたびに常に送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[進捗イベント発生] --> B[reportProgress呼び出し]
    B --> C[メッセージフォーマット]
    C --> D[RPCProcessor.log呼び出し]
    D --> E[JSON-RPCパケット構築]
    E --> F[sendRawPacket]
    F --> G[stdout経由で送信]
    G --> H[終了]
```

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

該当なし（LSPサーバーはデータベースを使用しない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | RPC接続が切断されている | 上位で処理 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

ログメッセージにはファイルパスやワークスペースURIが含まれる場合がある。個人情報は含まれない。

## 備考

- RPCProcessor.log()はテンプレート引数でMessageTypeを指定でき、デフォルトはMessageType.log
- reportProgress()はstartupTimeからの経過時間をミリ秒単位で計算し、ProgressType名と進捗ステップ情報を含むフォーマット済みメッセージを生成する
- progress.dのreportProgress()はrpc.logを直接呼び出すため、window/logMessage通知が直接送信される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protocol.d | `lsp/source/served/lsp/protocol.d` | LogMessageParams構造体（type: MessageType, message: string）の定義 |
| 1-2 | progress.d | `source/served/utils/progress.d` | ProgressType列挙値（globalStartup, configLoad等）の定義（16行目〜45行目） |

**読解のコツ**: ProgressTypeの各値にはwithProgress/optionalProgressアノテーションがあり、進捗付きかどうかを示す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | jsonrpc.d | `lsp/source/served/lsp/jsonrpc.d` | RPCProcessor.log()メソッド（353行目〜361行目）。テンプレート引数でMessageTypeを指定し、argsをtext()で結合してLogMessageParamsとして送信 |

**主要処理フロー**:
1. **353行目**: log()メソッド定義 - MessageType.logがデフォルト
2. **356行目**: JSON-RPCパケットを直接構築（notifyMethodを使わず、sendRawPacketを直接使用）
3. **357行目**: LogMessageParams(type, text(args))でパラメータ構築

#### Step 3: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | progress.d | `source/served/utils/progress.d` | reportProgress()関数（47行目〜64行目）。ProgressTypeと進捗情報をフォーマットしてrpc.logを呼び出す |
| 3-2 | extension.d | `source/served/extension.d` | reportProgressの各呼び出し箇所（67行目、389行目、582行目、624行目、790行目等） |

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

```
[extension.d / delayedProjectActivation / doStartup 等]
    |
    +-- reportProgress(type, step, max, args)    [progress.d:53]
            |
            +-- rpc.log(formattedMessage)         [jsonrpc.d:353]
                    |
                    +-- sendRawPacket(parts)       [jsonrpc.d:145]
                            |
                            +-- writer.put(...)    (stdout書き出し)
```

### データフロー図

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

ProgressType列挙値      -->  reportProgress()                 -->  フォーマット済み文字列
step/max値              -->  format!("...")                    -->  LogMessageParams
経過時間(MonoTime)      -->  RPCProcessor.log()               -->  JSON-RPCパケット
追加メッセージ引数      -->  sendRawPacket()                   -->  stdout(クライアントへ)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| jsonrpc.d | `lsp/source/served/lsp/jsonrpc.d` | ソース | RPCProcessor.log()メソッド（通知送信の中核） |
| protocol.d | `lsp/source/served/lsp/protocol.d` | ソース | LogMessageParams・MessageType等のLSPプロトコル型定義 |
| progress.d | `source/served/utils/progress.d` | ソース | reportProgress()関数（主要な呼び出し元） |
| extension.d | `source/served/extension.d` | ソース | reportProgressの各呼び出し箇所 |
| types.d | `source/served/types.d` | ソース | rpcエイリアス定義、startupTime変数定義 |
