docs(phase 104): .hako側ロギング設計ガイド確立
- Add Section 4 (.hako側ロギング方針) to logging_policy.md - Create hako_logging_design.md (comprehensive guide, 331 lines) - Define 4 logging categories (user-facing/dev-debug/monitoring/internal Rust) - Provide 3 logging box patterns (Lightweight/Structured/Contextual) - Add best practices and anti-patterns with code examples - Update ring0-inventory.md with Phase 104 entry - Cross-reference documentation for consistency This completes Phase 104: establishing user-facing logging guidelines for Nyash applications, complementing Rust-side logging policy from Phase 99-101. Files modified: - docs/development/current/main/logging_policy.md - docs/development/current/main/hako_logging_design.md (new) - docs/development/current/main/ring0-inventory.md Related: Phase 99 (logging policy design), Phase 100-101 (Rust impl)
This commit is contained in:
331
docs/development/current/main/hako_logging_design.md
Normal file
331
docs/development/current/main/hako_logging_design.md
Normal file
@ -0,0 +1,331 @@
|
||||
# Phase 104: .hako側ロギング設計ガイド
|
||||
|
||||
## 概要
|
||||
|
||||
Nyash(.hako)アプリケーションからのロギングを体系的に設計し、Ring0.log(Rust内部)
|
||||
との役割分担を明確にする。
|
||||
|
||||
## Architecture: 3層ロギングの完全図
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ ユーザーアプリケーション (.hako) │
|
||||
│ │
|
||||
│ box MyApp { │
|
||||
│ main() { │
|
||||
│ me.console.println("Result: OK") ← ConsoleBox │
|
||||
│ } │
|
||||
│ } │
|
||||
└──────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
ConsoleService
|
||||
(user-facing)
|
||||
│
|
||||
┌──────────────────▼──────────────────────────────────────┐
|
||||
│ Rust Runtime (Ring0.log) │
|
||||
│ │
|
||||
│ ring0.log.debug("[joinir] Processing...") ← internal
|
||||
│ ring0.log.error("VM error: {}") ← internal
|
||||
└──────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
stderr/stdout
|
||||
│
|
||||
┌───────▼────────┐
|
||||
│ Terminal │
|
||||
│ (user sees) │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
## ロギングの4つのカテゴリ
|
||||
|
||||
### 1. User-Facing (ユーザー向け)
|
||||
|
||||
**属性**: 常に表示(本番環境対応)
|
||||
**出力先**: ConsoleBox → stdout
|
||||
**制御**: フラグなし(常時有効)
|
||||
|
||||
**例**:
|
||||
```nyash
|
||||
box FileProcessor {
|
||||
console: ConsoleBox
|
||||
|
||||
process(filename) {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
if file_not_found(filename) {
|
||||
me.console.println("❌ File not found: " + filename)
|
||||
return -1
|
||||
}
|
||||
|
||||
me.console.println("✅ Processing: " + filename)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Dev-Debug (開発用デバッグ)
|
||||
|
||||
**属性**: 開発時のみ(本番環境では削除推奨)
|
||||
**出力先**: println!(局所的)
|
||||
**制御**: bool flag(環境変数or定数)
|
||||
|
||||
**例**:
|
||||
```nyash
|
||||
box MathBox {
|
||||
DEBUG: BoolBox = false // 環境変数から設定
|
||||
|
||||
calculate(a: Integer, b: Integer) {
|
||||
if DEBUG {
|
||||
print("[DEBUG] a=" + a + ", b=" + b)
|
||||
}
|
||||
return a + b
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Monitoring (運用監視)
|
||||
|
||||
**属性**: 定期レポート(本番環境で有効)
|
||||
**出力先**: ConsoleBox → stdout
|
||||
**制御**: 定期的(タイマーベース)
|
||||
|
||||
**例**:
|
||||
```nyash
|
||||
box ServiceMonitor {
|
||||
console: ConsoleBox
|
||||
requests_count: IntegerBox
|
||||
|
||||
tick() {
|
||||
me.console = new ConsoleBox()
|
||||
me.console.println("[PERF] Requests/sec: " + me.requests_count)
|
||||
me.requests_count = 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Internal Rust (内部実装)
|
||||
|
||||
**属性**: Rust実装の内部ログ
|
||||
**出力先**: Ring0.log → stderr
|
||||
**制御**: NYASH_RING0_LOG_LEVEL
|
||||
|
||||
**例** (.hako側には関係ない、参考):
|
||||
```rust
|
||||
// src/mir/builder.rs
|
||||
ring0.log.debug("[mir] Building function...");
|
||||
```
|
||||
|
||||
## ロギングBox設計パターン
|
||||
|
||||
### パターン 1: Lightweight Logger
|
||||
|
||||
用途: 単純なユースケース(メッセージのみ)
|
||||
|
||||
```nyash
|
||||
box SimpleLogger {
|
||||
console: ConsoleBox
|
||||
|
||||
birth() {
|
||||
me.console = new ConsoleBox()
|
||||
}
|
||||
|
||||
log(msg) {
|
||||
me.console.println(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用例
|
||||
box MyApp {
|
||||
main() {
|
||||
local logger = new SimpleLogger()
|
||||
logger.log("Processing...")
|
||||
logger.log("✅ Done")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### パターン 2: Structured Logger
|
||||
|
||||
用途: レベル分け(ERROR/WARN/INFO)
|
||||
|
||||
```nyash
|
||||
box StructuredLogger {
|
||||
console: ConsoleBox
|
||||
|
||||
birth() {
|
||||
me.console = new ConsoleBox()
|
||||
}
|
||||
|
||||
error(msg) {
|
||||
me.console.println("[ERROR] " + msg)
|
||||
}
|
||||
|
||||
warn(msg) {
|
||||
me.console.println("[WARN] " + msg)
|
||||
}
|
||||
|
||||
info(msg) {
|
||||
me.console.println("[INFO] " + msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用例
|
||||
box DatabaseConnector {
|
||||
logger: StructuredLogger
|
||||
|
||||
birth() {
|
||||
me.logger = new StructuredLogger()
|
||||
}
|
||||
|
||||
connect(host) {
|
||||
if network_unavailable() {
|
||||
me.logger.error("Network unavailable")
|
||||
return false
|
||||
}
|
||||
|
||||
me.logger.info("Connected to: " + host)
|
||||
return true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### パターン 3: Contextual Logger
|
||||
|
||||
用途: コンテキスト情報を含むログ
|
||||
|
||||
```nyash
|
||||
box ContextualLogger {
|
||||
console: ConsoleBox
|
||||
context: StringBox // operation_id等
|
||||
|
||||
birth(ctx) {
|
||||
me.console = new ConsoleBox()
|
||||
me.context = ctx
|
||||
}
|
||||
|
||||
log(msg) {
|
||||
me.console.println("[" + me.context + "] " + msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用例
|
||||
box RequestHandler {
|
||||
logger: ContextualLogger
|
||||
|
||||
birth(request_id) {
|
||||
me.logger = new ContextualLogger(request_id)
|
||||
}
|
||||
|
||||
process() {
|
||||
me.logger.log("Request started")
|
||||
// ... 処理 ...
|
||||
me.logger.log("Request completed")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ベストプラクティス
|
||||
|
||||
### ✅ DO (推奨)
|
||||
|
||||
1. **一元化**: ロギングBoxを1つ所有
|
||||
```nyash
|
||||
box MyApp {
|
||||
logger: LoggerBox // ← 一箇所だけ
|
||||
main() { ... }
|
||||
}
|
||||
```
|
||||
|
||||
2. **構造化**: メッセージは構造化
|
||||
```nyash
|
||||
logger.log("[OPERATION] " + op_name + " status=" + status)
|
||||
```
|
||||
|
||||
3. **条件付き**: デバッグログにフラグ
|
||||
```nyash
|
||||
if debug_enabled {
|
||||
logger.debug("var=" + var)
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ DON'T (回避)
|
||||
|
||||
1. **散乱**: 複数の ConsoleBox 初期化
|
||||
```nyash
|
||||
// ❌ ダメ
|
||||
box MyApp {
|
||||
main() {
|
||||
local c1 = new ConsoleBox()
|
||||
local c2 = new ConsoleBox() // 重複
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **混在**: データ処理ロジックとログ混在
|
||||
```nyash
|
||||
// ❌ ダメ
|
||||
box Processor {
|
||||
process(x) {
|
||||
print(x) // ← ロジックに埋め込み
|
||||
return x + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **過剰**: 全行でログ出力
|
||||
```nyash
|
||||
// ❌ ダメ
|
||||
calculate(a, b) {
|
||||
print("enter")
|
||||
local x = a + b
|
||||
print("x=" + x)
|
||||
print("exit")
|
||||
return x
|
||||
}
|
||||
```
|
||||
|
||||
## ロギング制御フロー
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ .hako app start │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────▼──────────────────────────┐
|
||||
│ Check NYASH_RING0_LOG_LEVEL env │
|
||||
└────┬──────────────────────────┘
|
||||
│
|
||||
┌────▼────────────┐ ┌──────────────────┐
|
||||
│ DEBUG level? │─Y─> │ Enable full logs │
|
||||
└────┬────────────┘ └──────────────────┘
|
||||
│
|
||||
N
|
||||
┌────▼────────────┐ ┌──────────────────┐
|
||||
│ INFO level? │─Y─> │ Error/Warn only │
|
||||
└────┬────────────┘ └──────────────────┘
|
||||
│
|
||||
N (default)
|
||||
┌────▼──────────────┐
|
||||
│ User-facing only │
|
||||
│ (ConsoleBox) │
|
||||
└───────────────────┘
|
||||
```
|
||||
|
||||
## チェックリスト: ロギング設計確認
|
||||
|
||||
実装時には以下をチェック:
|
||||
|
||||
- [ ] ConsoleBox初期化は1回のみ
|
||||
- [ ] ユーザーメッセージは全て ConsoleBox経由
|
||||
- [ ] デバッグログに "[DEBUG]" prefix
|
||||
- [ ] エラーメッセージに "❌" 絵文字
|
||||
- [ ] 成功メッセージに "✅" 絵文字
|
||||
- [ ] ロギングLogicを別Boxに分離した
|
||||
- [ ] テストコード内の println! は許容
|
||||
- [ ] 本番環境での不要なログを削除した
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
- [logging_policy.md](logging_policy.md) - Rust/Ring0.log側方針
|
||||
- [ring0-inventory.md](ring0-inventory.md) - println!分類在庫
|
||||
- [core_optional_design.md](core_optional_design.md) - Optional化設計
|
||||
@ -292,8 +292,187 @@ Focus on high-impact migrations first, defer low-priority changes.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
## Section 4: .hako側ロギング方針 (Phase 104)
|
||||
|
||||
### 概要
|
||||
|
||||
Nyash(.hako)アプリケーションからのロギングは、ConsoleBoxを通じてユーザーに伝える方式に統一。
|
||||
|
||||
### パターン分類
|
||||
|
||||
#### Pattern 1: ユーザー向けメッセージ(user-facing)
|
||||
|
||||
**用途**: ユーザーに表示される情報
|
||||
- エラーメッセージ
|
||||
- 進捗情報
|
||||
- 成功/完了通知
|
||||
|
||||
**実装方法**:
|
||||
```nyash
|
||||
box MyApp {
|
||||
console: ConsoleBox
|
||||
|
||||
main() {
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
// ✅ 正しい方法: ConsoleBox経由
|
||||
me.console.println("Processing started...")
|
||||
|
||||
// 実装例: エラーハンドリング
|
||||
if error_occurred {
|
||||
me.console.println("❌ Error: " + error_msg)
|
||||
return 1
|
||||
}
|
||||
|
||||
me.console.println("✅ Success!")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**ガイドライン**:
|
||||
- すべてのユーザー向けメッセージは ConsoleBox.println() 使用
|
||||
- エラーメッセージは "❌" 絵文字で開始
|
||||
- 成功メッセージは "✅" 絵文字で開始
|
||||
- 進捗は "[1/10]" などの形式で表示
|
||||
|
||||
#### Pattern 2: デバッグ/診断ログ(dev-debug)
|
||||
|
||||
**用途**: 開発時のデバッグ情報
|
||||
- 変数値のダンプ
|
||||
- 関数entry/exit
|
||||
- 分岐の選択記録
|
||||
|
||||
**実装方法** (Phase 104では ユーザーアプリ側は println! 許容):
|
||||
```nyash
|
||||
box MyApp {
|
||||
main() {
|
||||
// 現在: ユーザーアプリが debug print 時は println! OK
|
||||
// 将来 (Phase 105): ユーザー定義ロギングフレームワーク検討
|
||||
|
||||
local debug_enabled = false // 環境変数から読む
|
||||
if debug_enabled {
|
||||
print("[DEBUG] Processing item: " + item_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**ガイドライン**:
|
||||
- デバッグ出力は "[DEBUG]" prefix で統一
|
||||
- bool flag で on/off 制御(環境変数参照)
|
||||
- 本番環境では全削除推奨
|
||||
|
||||
#### Pattern 3: 監視/メトリクス(monitoring)
|
||||
|
||||
**用途**: 運用時の監視情報
|
||||
- 実行時間計測
|
||||
- メモリ使用量
|
||||
- 処理レート
|
||||
|
||||
**実装方法**:
|
||||
```nyash
|
||||
box PerformanceMonitor {
|
||||
console: ConsoleBox
|
||||
start_time: IntegerBox
|
||||
|
||||
begin() {
|
||||
me.console = new ConsoleBox()
|
||||
me.start_time = runtime.now()
|
||||
}
|
||||
|
||||
report() {
|
||||
local elapsed = runtime.now() - me.start_time
|
||||
me.console.println("[PERF] Elapsed: " + elapsed + "ms")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**ガイドライン**:
|
||||
- メトリクスは "[PERF]" prefix で統一
|
||||
- 定期レポーティング推奨
|
||||
- Ring0.log(Rust側)と連携可能(将来拡張)
|
||||
|
||||
### 設計原則(.hako側視点)
|
||||
|
||||
1. **Single Responsibility**: 各Boxは1つのロギング目的に専念
|
||||
2. **Testability**: ログ出力をテスト可能にする(interface化)
|
||||
3. **Composability**: ロギングBoxを組み合わせる
|
||||
4. **Zero Config Default**: 環境変数なしでもロギング動作
|
||||
|
||||
### アンチパターン(避けるべき書き方)
|
||||
|
||||
```nyash
|
||||
// ❌ ダメな例 1: raw println!を散乱
|
||||
print("value: " + x) // → Boxにロギング機能を出す
|
||||
|
||||
// ❌ ダメな例 2: ConsoleBoxの多重初期化
|
||||
box MyBox {
|
||||
main() {
|
||||
local console = new ConsoleBox()
|
||||
console.println("msg1")
|
||||
|
||||
local console2 = new ConsoleBox() // ← 重複初期化
|
||||
console2.println("msg2")
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ ダメな例 3: ロギングロジック混在
|
||||
box DataProcessor {
|
||||
process(data) {
|
||||
if validate(data) {
|
||||
print("OK") // ← 出力ロジックが混在
|
||||
return process_data(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 正しい例: 責務分離
|
||||
box DataProcessor {
|
||||
logger: LoggerBox
|
||||
|
||||
process(data) {
|
||||
if validate(data) {
|
||||
return process_data(data)
|
||||
} else {
|
||||
me.logger.error("Validation failed")
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 今後の拡張予定
|
||||
|
||||
**Phase 105**: ユーザー定義ロギングフレームワーク
|
||||
- Logger Box interface化
|
||||
- ログレベル統一(DEBUG/INFO/WARN/ERROR)
|
||||
- Structured logging (JSON形式)
|
||||
|
||||
**Phase 106**: ログ出力先の切り替え
|
||||
- ConsoleBox → FileBox
|
||||
- ConsoleBox → NetworkBox
|
||||
- Pluggable logger architecture
|
||||
|
||||
### テストでのロギング
|
||||
|
||||
テストコード内のロギング/println!は許容:
|
||||
```nyash
|
||||
// ✅ テストコード内
|
||||
test my_test {
|
||||
local result = my_function()
|
||||
print("Result: " + result) // テスト内 OK
|
||||
assert(result == expected)
|
||||
}
|
||||
```
|
||||
|
||||
**理由**: テストは隔離環境実行のため、ログ管理の必要がない
|
||||
|
||||
---
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
- [.hako側ロギング設計](hako_logging_design.md) - Phase 104 ユーザーアプリ視点
|
||||
- [Ring0 Inventory](ring0-inventory.md) - println! categorization and Ring0.log plans
|
||||
- [CoreBoxes Design - Section 15.6-A](core_boxes_design.md#section-156-a-logsoutput-unified-design) - Architectural context
|
||||
- [Phase 85 CURRENT_TASK](../../../CURRENT_TASK.md) - Implementation timeline
|
||||
|
||||
@ -326,6 +326,20 @@ ring0.log.debug(&format!("Operation completed in {}ms", duration));
|
||||
**Other**: ~277 locations
|
||||
- TBD
|
||||
|
||||
### Phase 104: .hako側ロギング設計 (COMPLETED)
|
||||
|
||||
**Scope**:
|
||||
- ConsoleBox適切な使い方ガイド
|
||||
- ユーザー定義Boxからのロギングベストプラクティス
|
||||
- 4つのロギングカテゴリ確立(user-facing/dev-debug/monitoring/internal Rust)
|
||||
- 3つのロギングBoxパターン(Lightweight/Structured/Contextual)
|
||||
|
||||
**Files Created/Updated**:
|
||||
- docs/development/current/main/logging_policy.md (Section 4 追加)
|
||||
- docs/development/current/main/hako_logging_design.md (new)
|
||||
|
||||
**Status**: Complete - .hako側ロギング設計確立
|
||||
|
||||
---
|
||||
|
||||
## Section 5: Migration Roadmap
|
||||
|
||||
Reference in New Issue
Block a user