# 帳票設計書 29-Console Logger

## 概要

本ドキュメントは、webpackのビルドプロセスにおけるログメッセージをコンソールに出力するConsole Loggerの設計仕様を定義する。lib/logging/createConsoleLogger.jsおよびlib/logging/Logger.jsに基づく。

### 本帳票の処理概要

Console Loggerは、webpackのビルドプロセスで発生するログメッセージをコンソールに出力するロギングシステムである。ログレベル（error/warn/info/log/verbose/debug）によるフィルタリング機能を提供し、指定レベル以上のメッセージのみを出力する。WebpackLoggerクラスがログの生成インターフェースを提供し、createConsoleLoggerが実際のコンソール出力ロジックを担う。

**業務上の目的・背景**：webpackのビルドプロセスは多数のプラグイン・ローダーが連携して動作するため、各コンポーネントの動作状況をログとして記録・出力する仕組みが必要である。Console Loggerはビルド中の情報出力を一元管理し、ログレベルによるフィルタリングでノイズを制御する。デバッグ時には特定モジュールのデバッグログを有効化するフィルタ機能も提供する。

**帳票の利用シーン**：ビルドプロセスの詳細ログ確認、プラグイン・ローダーのデバッグ、ビルドエラー・警告の調査、パフォーマンス計測（timeメソッド）、特定モジュールのデバッグフィルタリング。

**主要な出力内容**：
1. エラーメッセージ（console.error）
2. 警告メッセージ（console.warn）
3. 情報メッセージ（console.info）
4. 通常ログメッセージ（console.log）
5. デバッグメッセージ（console.debug）
6. 処理時間計測結果（timeログ）
7. グループ化されたログ（group/groupCollapsed/groupEnd）
8. ステータスメッセージ（console.status または console.info）
9. プロファイル情報（console.profile/profileEnd）
10. トレース情報（console.trace）

**帳票の出力タイミング**：ビルドプロセス中に各プラグイン・ローダーがWebpackLoggerのメソッドを呼び出すたびにリアルタイムで出力される。ログレベルとデバッグフィルタの設定に基づいてフィルタリングされる。

**帳票の利用者**：webpack開発者、プラグイン開発者、フロントエンド開発者

## 帳票種別

ログレポート（リアルタイムコンソール出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLI | webpack | ビルド実行時に自動出力 |
| - | webpack設定ファイル | webpack.config.js | infrastructureLogging オプション |
| - | Node.js API | - | compiler.getInfrastructureLogger(name) |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（コンソール出力） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | 該当なし（標準出力/標準エラー出力） |
| 出力方法 | console.error/warn/info/log/debug |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

Console Loggerの出力フォーマットはログタイプごとに異なる。全てのメッセージにはロガー名が`[name]`プレフィックスとして付与される。

```
[logger-name] error message          ... console.error
[logger-name] warning message        ... console.warn
[logger-name] info message           ... console.info
[logger-name] log message            ... console.log
[logger-name] debug message          ... console.debug
[logger-name] label: XX.XXX ms       ... time measurement
[logger-name] group label            ... group start
  (grouped content)
                                     ... group end
```

### ヘッダー部

該当なし

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | name | ロガー名 | getLogger(name) | [name] プレフィックス | - |
| 2 | type | ログタイプ | LogType enum | error/warn/info/log/debug/trace/group/time/status等 | - |
| 3 | args | ログメッセージ・引数 | 呼び出し元 | 可変長引数 | - |

### フッター部

該当なし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ログレベル設定 | level: "none"\|"error"\|"warn"\|"info"\|"log"\|"verbose" | No（デフォルト: "info"） |
| デバッグフィルタ | debug: boolean \| string[] \| RegExp[] \| Function[] | No（デフォルト: false） |

### ソート順

該当なし（時系列で出力）

### 改ページ条件

該当なし

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

### 参照テーブル一覧

データベースは参照しない。

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| time (ms) | start * 1000 + end / 1000000 | なし | process.hrtime()の[seconds, nanoseconds]から算出 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[WebpackLogger.error/warn/info/log/debug呼出] --> B[LOG_SYMBOL経由でLogFn実行]
    B --> C{runtime.hooks.logフック}
    C -->|undefined| D[currentDefaultLogger呼出]
    C -->|値あり| E[フック処理に委譲]
    D --> F{debugFilters チェック}
    F -->|debug有効| G[全ログタイプ出力]
    F -->|debug無効| H{loglevelチェック}
    H -->|閾値以上| I[console.error/warn/info/log出力]
    H -->|閾値未満| J[出力抑制]
    I --> K[labeledArgs生成]
    K --> L[コンソール出力]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 不正なLogType | 未定義のLogTypeが指定された場合 | Unexpected LogType {type} | 定義済みのLogType値を使用する |
| timeEnd未開始 | time()を呼ばずにtimeEnd()を呼んだ場合 | No such label '{label}' for WebpackLogger.timeEnd() | 事前にtime(label)を呼び出す |
| timeLog未開始 | time()を呼ばずにtimeLog()を呼んだ場合 | No such label '{label}' for WebpackLogger.timeLog() | 事前にtime(label)を呼び出す |
| timeAggregate未開始 | time()を呼ばずにtimeAggregate()を呼んだ場合 | No such label '{label}' for WebpackLogger.timeAggregate() | 事前にtime(label)を呼び出す |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ログメッセージ数に依存（制限なし） |
| 目標出力時間 | リアルタイム（各メッセージ即座に出力） |
| 同時出力数上限 | 制限なし |

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

ログメッセージにファイルパス、モジュール名、設定値等が含まれる場合がある。本番環境ではログレベルを"warn"以上に設定し、不要な情報の出力を抑制することが推奨される。debugフィルタは開発環境でのみ使用すること。

## 備考

- ログレベルの数値マッピング（行68-77）：none=6, false=6, error=5, warn=4, info=3, log=2, true=2, verbose=1
- debugフィルタ有効時はログレベルに関係なく全メッセージが出力される
- groupCollapsedはverboseレベルを超える場合にgroupにフォールスルーする
- status タイプはconsole.statusメソッドが存在する場合はそれを使用し、存在しない場合はconsole.infoにフォールバックする
- clear タイプはconsole.clearを呼び出す
- runtime.js（行13-17）でデフォルトロガーオプションが定義：level: "info", debug: false, console: global console
- runtime.jsのhooks.logフックにより、ログ出力をインターセプト可能
- WebpackLoggerのgetChildLogger()により階層的なロガーを作成可能（name/childName形式）
- timeAggregate/timeAggregateEndにより、複数の計測結果を集約して報告可能

---

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

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

### 推奨読解順序

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

ログタイプの定義とWebpackLoggerクラスの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Logger.js | `lib/logging/Logger.js` | 行8-28: LogType定数の定義（error/warn/info/log/debug/trace/group/groupCollapsed/groupEnd/profile/profileEnd/time/clear/status） |
| 1-2 | Logger.js | `lib/logging/Logger.js` | 行43-53: WebpackLoggerクラスのコンストラクタ（LOG_SYMBOL, getChildLogger） |

**読解のコツ**: LogTypeはObject.freeze()で凍結された列挙型オブジェクト。WebpackLoggerはLOG_SYMBOL(Symbol)をキーとしてログ関数を内部に保持し、各public メソッド（error, warn, info等）がそれを呼び出す。

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

ロガーの生成と出力先の決定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | runtime.js | `lib/logging/runtime.js` | 行13-17: デフォルトロガーオプション（level: "info", debug: false, console） |
| 2-2 | runtime.js | `lib/logging/runtime.js` | 行33-41: getLogger()関数 - WebpackLoggerインスタンスの生成とhooks.logフックの呼び出し |
| 2-3 | runtime.js | `lib/logging/runtime.js` | 行43-45: hooks.log - SyncBailHookによるログ出力のインターセプト機構 |

**主要処理フロー**:
1. **行36**: `hooks.log.call(name, type, args)` でフックを呼び出し
2. **行36-37**: フックがundefinedを返した場合、`currentDefaultLogger(name, type, args)` を呼び出し
3. **行40**: `getChildLogger` で子ロガーを作成可能（`name/childName`形式）

#### Step 3: コンソール出力ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | createConsoleLogger.js | `lib/logging/createConsoleLogger.js` | 行68-77: LogLevel数値マッピング（none=6, error=5, warn=4, info=3, log=2, verbose=1） |
| 3-2 | createConsoleLogger.js | `lib/logging/createConsoleLogger.js` | 行83-93: ファクトリ関数の入口 - debugFilters生成とloglevel計算 |
| 3-3 | createConsoleLogger.js | `lib/logging/createConsoleLogger.js` | 行101-215: logger関数 - ログタイプごとのswitch文による出力制御 |

**主要処理フロー**:
- **行106-113**: labeledArgs()関数 - `[name] message` 形式のプレフィックス付き引数を生成
- **行115**: debugFiltersのチェック - debug=trueの場合は全ログが出力される
- **行116-214**: LogTypeごとのswitch文 - 各タイプに応じたconsoleメソッド呼び出しとログレベルフィルタリング

#### Step 4: WebpackLoggerのメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Logger.js | `lib/logging/Logger.js` | 行58-131: 基本ログメソッド（error/warn/info/log/debug/assert/trace/clear/status/group/groupCollapsed/groupEnd/profile/profileEnd） |
| 4-2 | Logger.js | `lib/logging/Logger.js` | 行150-220: 時間計測メソッド（time/timeLog/timeEnd/timeAggregate/timeAggregateEnd） |

**主要処理フロー**:
- **行150-153**: time() - process.hrtime()で計測開始、TIMERS_SYMBOLマップに保存
- **行171-179**: timeEnd() - hrtime差分を計算、LogType.timeでログ出力
- **行185-209**: timeAggregate() - 集約計測、TIMERS_AGGREGATES_SYMBOLマップに蓄積

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

```
compiler.getInfrastructureLogger("plugin-name")
    |
    +-- runtime.getLogger("plugin-name")
            |
            +-- new WebpackLogger(logFn, getChildLogger)
                    |
                    +-- logFn = (type, args) => {
                    |       hooks.log.call(name, type, args)
                    |       || currentDefaultLogger(name, type, args)
                    |   }
                    |
                    +-- .error(...args) --> LOG_SYMBOL(LogType.error, args)
                    +-- .warn(...args)  --> LOG_SYMBOL(LogType.warn, args)
                    +-- .info(...args)  --> LOG_SYMBOL(LogType.info, args)
                    +-- .log(...args)   --> LOG_SYMBOL(LogType.log, args)
                    +-- .debug(...args) --> LOG_SYMBOL(LogType.debug, args)
                    +-- .time(label)    --> TIMERS_SYMBOL.set(label, hrtime)
                    +-- .timeEnd(label) --> LOG_SYMBOL(LogType.time, [label, ...hrtime])
                    +-- .status(args)   --> LOG_SYMBOL(LogType.status, args)

currentDefaultLogger = createConsoleLogger(options)
    |
    +-- logger(name, type, args)
            |
            +-- debugFilters チェック
            +-- loglevel チェック
            +-- switch(type)
                +-- error  --> console.error([name] args)
                +-- warn   --> console.warn([name] args)
                +-- info   --> console.info([name] args)
                +-- log    --> console.log([name] args)
                +-- debug  --> console.debug([name] args)
                +-- time   --> console.log([name] label: XX ms)
                +-- status --> console.status([name] args) || console.info
                +-- group  --> console.group([name] args)
                +-- trace  --> console.trace()
                +-- clear  --> console.clear()
```

### データフロー図

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

プラグイン/ローダー            WebpackLogger                      コンソール
  logger.error(msg)     --->   LOG_SYMBOL(error, [msg])      ---> console.error
  logger.warn(msg)      --->   LOG_SYMBOL(warn, [msg])       ---> console.warn
  logger.info(msg)      --->   LOG_SYMBOL(info, [msg])       ---> console.info
  logger.log(msg)       --->   LOG_SYMBOL(log, [msg])        ---> console.log
  logger.debug(msg)     --->   LOG_SYMBOL(debug, [msg])      ---> console.debug

                               runtime.hooks.log
                                   |
                               createConsoleLogger
                                   |
                              debugFilters + loglevel
                                   |
infrastructureLogging      フィルタリング判定              出力 or 抑制
  level: "info"       ---> loglevel = LogLevel["info"] = 3
  debug: false        ---> debugFilters = [() => false]
                               |
                          labeledArgs()
                          "[name] message"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| createConsoleLogger.js | `lib/logging/createConsoleLogger.js` | ソース | コンソール出力ロジック（ログレベルフィルタ・デバッグフィルタ・タイプ別出力） |
| Logger.js | `lib/logging/Logger.js` | ソース | WebpackLoggerクラス（LogType定義・ログメソッド・時間計測メソッド） |
| runtime.js | `lib/logging/runtime.js` | ソース | ロガーランタイム（getLogger・configureDefaultLogger・hooks.log） |
| Compiler.js | `lib/Compiler.js` | ソース | getInfrastructureLogger()メソッド提供 |
| Compilation.js | `lib/Compilation.js` | ソース | getLogger()メソッド提供 |
