Skip to content

Lesson 10: エラーログの解析

クラス: 初級
所要時間: 約35分
前提知識: 初級 Lesson 1〜9 完了済み


1. 解説

エラーログの種類と読み方

ログタイプ内容
スタックトレースエラー発生箇所の呼び出し履歴at Function.processOrder (app.js:42:5)
エラーコードOS・ライブラリ固有のコードENOENT, ECONNREFUSED, ETIMEDOUT
HTTPステータスAPI/Webのエラー500 Internal Server Error
ヘルスチェックログアプリの状態Database: DISCONNECTED

よく見る Node.js エラーコード

ENOENT     → ファイル・ディレクトリが存在しない
EACCES     → アクセス権限がない
EADDRINUSE → ポートが使用中
ECONNREFUSED → 接続拒否(サービスが起動していない)
ETIMEDOUT  → タイムアウト
ENOMEM     → メモリ不足

ログからバグを特定する思考プロセス

1. エラーメッセージの種類を特定
2. スタックトレースで発生箇所を特定
3. 「いつ」「何を」したときに発生したか確認
4. 直前のログを見て状態を把握
5. コードで原因を確認して修正

2. 実践

Step 1: ログ生成アプリを作成

bash
mkdir -p ~/claude-practice/elementary/lesson10
cd ~/claude-practice/elementary/lesson10

cat > app.js << 'EOF'
const fs = require('fs');
const path = require('path');

class Logger {
  constructor(logFile) {
    this.logFile = logFile;
    this.logs = [];
  }
  
  log(level, message, meta = {}) {
    const entry = {
      timestamp: new Date().toISOString(),
      level,
      message,
      ...meta
    };
    this.logs.push(entry);
    const line = JSON.stringify(entry) + '\n';
    fs.appendFileSync(this.logFile, line);
    console.log(`[${level}] ${message}`);
  }
  
  info(msg, meta) { this.log('INFO', msg, meta); }
  warn(msg, meta) { this.log('WARN', msg, meta); }
  error(msg, meta) { this.log('ERROR', msg, meta); }
}

const logger = new Logger('app.log');

// シミュレーション
logger.info('Application started', { version: '1.0.0', port: 3000 });
logger.info('Database connected', { host: 'localhost', db: 'myapp' });
logger.info('Processing 150 orders');
logger.warn('High memory usage detected', { memoryMB: 850, threshold: 800 });
logger.error('Payment service timeout', { orderId: 'ORD-1234', elapsed: 5001 });
logger.info('Retrying payment service');
logger.error('Payment service unreachable', { orderId: 'ORD-1234', attempts: 3 });
logger.error('Order failed, rolling back', { orderId: 'ORD-1234' });
logger.warn('Database connection pool exhausted', { active: 20, max: 20 });
logger.error('Unhandled exception', {
  error: 'TypeError: Cannot read properties of null',
  stack: 'at processPayment (payment.js:87:14)\n  at Order.complete (order.js:156:5)',
  orderId: 'ORD-1235'
});

console.log('Log written to app.log');
EOF

node app.js

Step 2: ログの解析を依頼

bash
claude
app.log を読んで、以下を分析してください:

1. エラーの一覧と発生時刻
2. エラーの根本原因の推測
3. 最も緊急度が高い問題
4. 対処すべき順序の提案

Step 3: 特定エラーの深掘り

app.log に記録されている 'Payment service' 関連のエラーについて:
1. エラーが発生するまでの流れを追ってください
2. 考えられる原因を3つ挙げてください
3. 各原因を調査するための確認方法を教えてください

Step 4: ログ集計と可視化

app.log を読んで、以下を集計してください:
- 時系列でのエラー発生パターン
- ERROR / WARN / INFO の件数
- 最もエラーが関連している orderId
- メトリクスのサマリー(メモリ使用量、接続プール状態など)

3. 確認課題(Assignment)

課題 10-1: 複雑なスタックトレースの解析

bash
cat > ~/claude-practice/elementary/lesson10/error.log << 'EOF'
2024-01-15T09:00:01.000Z INFO Server started port=3000
2024-01-15T09:00:02.000Z INFO Connected to database
2024-01-15T09:15:33.221Z ERROR UnhandledPromiseRejection
  Error: SQLITE_CONSTRAINT: UNIQUE constraint failed: users.email
      at Statement.pluck.Statement.run (/app/node_modules/better-sqlite3/lib/statement.js:78:14)
      at UserRepository.create (/app/src/repositories/user.js:45:20)
      at UserService.register (/app/src/services/user.js:23:35)
      at Router.post (/app/src/routes/auth.js:15:30)
      at Layer.handle (/app/node_modules/express/lib/router/layer.js:95:5)
2024-01-15T09:15:33.225Z WARN Unhandled error sent to client status=500
2024-01-15T09:18:44.110Z ERROR ENOENT: no such file or directory, open '/app/uploads/avatar_99.png'
      at Object.openSync (node:fs:600:18)
      at Object.readFileSync (node:fs:468:35)
      at ProfileController.getAvatar (/app/src/controllers/profile.js:67:20)
2024-01-15T09:30:00.000Z INFO Health check: OK
2024-01-15T09:45:22.889Z ERROR Connection to Redis lost
  Error: connect ECONNREFUSED 127.0.0.1:6379
      at TCPConnectWrap.afterConnect (/app/node_modules/ioredis/lib/redis/event_handler.js:121:14)
2024-01-15T09:45:22.891Z WARN Session store unavailable, falling back to memory
2024-01-15T09:45:55.003Z ERROR Redis reconnect attempt 1/3 failed
2024-01-15T09:46:25.441Z ERROR Redis reconnect attempt 2/3 failed
2024-01-15T09:46:55.779Z ERROR Redis reconnect attempt 3/3 failed - giving up
2024-01-15T09:46:55.780Z WARN Running without Redis - sessions are not persistent
EOF
error.log を読んで:
1. 発生したエラーを種類別に分類してください
2. 各エラーの根本原因を特定してください
3. 修正の優先順位をつけて、対処法を提案してください
4. このログからわかるシステムの問題点をまとめてください

達成条件: 3種類のエラー(UNIQUE制約、ENOENT、ECONNREFUSED)がすべて特定され、原因と対処法が正確に提案されること

課題 10-2: ログ解析スクリプトの作成

error.log のようなフォーマットのログファイルを解析する
log_analyzer.js を作成してください。

機能:
- parseLog(logContent): ログを構造化データに変換
- filterByLevel(logs, level): レベルでフィルタリング
- groupByHour(logs): 時間帯別に集計
- findMostFrequentErrors(logs, topN=5): 頻出エラートップN
- generateReport(logFile): ファイルを読んでサマリーをテキストで出力

node log_analyzer.js error.log で実行できること

達成条件: node log_analyzer.js error.log が実行できてサマリーが出力されること

課題 10-3: エラー検知の自動化

以下の機能を持つ error_monitor.js を作成してください:

- ログファイルを監視して新しい ERROR を検知
- ERROR が5分以内に3回以上発生したらアラートを出力
- アラート内容:エラーメッセージ、発生回数、最初と最後の時刻

node error_monitor.js app.log で起動できること

達成条件: エラーの頻度監視ロジックが正しく動作すること(fs.watchFile を使用)


自己チェックリスト


次の型

Lesson 11: 依存パッケージの管理 →

Claude Code Dojo