第一节:日志系统架构
日志级别与输出

作者:小学子 📚 | 日期:2026年4月2日 | 第八阶段 · 模块八


# 第八阶段 · 模块八 · 第一节:日志系统架构

核心问题

Claude Code 的日志系统是如何设计的?日志存储在哪里?如何读取和分析日志?


◇ 本节位置


        Claude Code 全局架构
        
        ┌─────────────────────────────────────────────────────────────────────┐
        │  调试与日志 ← 本节                                                 │
        │                                                                      │
        │  日志系统架构                                                        │
        │  ├── logError ──> 错误日志                                         │
        │  ├── logEvent ──> 事件日志                                         │
        │  └── 日志存储 ──> ~/.claude/logs                                   │
        └─────────────────────────────────────────────────────────────────────┘
        


一、日志系统概述

1.1 日志类型


        // Claude Code 日志类型:
        
        // 1. 错误日志
        // - logError()
        // - 记录异常和错误
        // - 位置:~/.claude/logs/errors/
        
        // 2. 事件日志
        // - logEvent()
        // - 记录重要事件
        // - 位置:~/.claude/logs/events/
        
        // 3. 调试日志
        // - logForDebugging()
        // - 仅在 --verbose 模式启用
        // - 位置:~/.claude/debug/latest
        

1.2 日志存储位置


        // 源码位置:src/utils/log.ts
        
        const LOG_PATHS = {
          errors: '~/.claude/logs/errors',
          events: '~/.claude/logs/events',
          debug: '~/.claude/debug/latest',
          sessions: '~/.claude/logs/sessions',
        };
        

1.3 五问分析

问 1:日志默认开启吗?


        // 错误日志:始终开启
        logError('Something went wrong');
        
        // 事件日志:需要配置
        logEvent({ type: 'tool_call', data: ... });
        
        // 调试日志:仅 --verbose 模式
        claude --verbose
        


二、错误日志

2.1 logError 函数

源码位置:`src/utils/log.ts` 第 158 行


        export function logError(error: unknown): void {
          const err = toError(error);
        
          // 检查是否禁用错误报告
          if (isEnvTruthy(process.env.DISABLE_ERROR_REPORTING)) {
            return;
          }
        
          const errorInfo = {
            error: err.stack || err.message,
            timestamp: new Date().toISOString(),
          };
        
          // 添加到内存日志
          addToInMemoryErrorLog(errorInfo);
        
          // 写入文件
          errorLogSink.logError(err);
        }
        

2.2 错误分类


        // 错误类型:
        
        interface ErrorInfo {
          error: string;       // 错误消息
          timestamp: string;   // 时间戳
          sessionId?: string; // 会话 ID
          context?: string;    // 错误上下文
        }
        
        // 常见错误类型:
        // - APIError:API 调用错误
        // - ToolError:工具执行错误
        // - AuthError:认证错误
        // - NetworkError:网络错误
        

2.3 五问分析

问 1:HARD FAIL 模式是什么?


        // 源码位置:log.ts 第 154 行
        
        const isHardFailMode = (): boolean => {
          return process.argv.includes('--hard-fail');
        };
        
        // 启用后,任何 logError 调用都会导致程序退出
        if (isHardFailMode()) {
          console.error('[HARD FAIL] logError called');
          process.exit(1);
        }
        


三、事件日志

3.1 logEvent 函数


        interface LogEvent {
          type: string;        // 事件类型
          timestamp: string;    // 时间戳
          data: unknown;        // 事件数据
          sessionId?: string;  // 会话 ID
        }
        
        // 事件类型示例
        const EVENT_TYPES = {
          SESSION_START: 'session_start',
          SESSION_END: 'session_end',
          TOOL_CALL: 'tool_call',
          TOOL_RESULT: 'tool_result',
          COMMAND: 'command',
          MODEL_CHANGE: 'model_change',
        };
        

3.2 日志格式


        {
          "type": "tool_call",
          "timestamp": "2026-04-02T10:30:00.000Z",
          "sessionId": "abc123",
          "data": {
            "tool": "Read",
            "input": { "file_path": "a.txt" }
          }
        }
        

3.3 五问分析

问 1:事件日志有什么用?


        // 1. 问题排查
        // 查看特定事件的完整上下文
        
        // 2. 性能分析
        // 分析工具调用频率和耗时
        
        // 3. 使用统计
        // 了解用户使用模式
        


四、调试日志

4.1 logForDebugging


        export function logForDebugging(
          message: string,
          context?: Record<string, unknown>,
        ): void {
          if (!isVerboseMode()) {
            return;
          }
        
          const entry = {
            timestamp: new Date().toISOString(),
            message,
            context,
          };
        
          console.log('[DEBUG]', JSON.stringify(entry, null, 2));
        }
        

4.2 调试模式启用


        # 启用调试模式
        claude --verbose
        
        # 或
        claude --debug
        
        # 查看实时调试日志
        tail -f ~/.claude/debug/latest
        

4.3 五问分析

问 1:verbose 和 debug 的区别?


        // --verbose:详细输出
        // - 显示所有调试信息
        // - 包括 API 请求/响应
        
        // --debug:调试模式
        // - 更详细的调试信息
        // - 包括堆栈跟踪
        


五、日志分析

5.1 查看日志


        # 查看最近错误
        ls -la ~/.claude/logs/errors/
        
        # 查看特定会话
        cat ~/.claude/logs/sessions/<session-id>.json
        
        # 搜索错误
        grep -r "Error" ~/.claude/logs/errors/
        

5.2 日志分析工具


        // 内置日志分析
        claude logs analyze
        
        // 输出:
        // - 错误统计
        // - 工具使用频率
        // - API 调用次数
        // - 平均响应时间
        

5.3 五问分析

问 1:日志保留多久?


        // 日志保留策略
        const LOG_RETENTION = {
          errors: '90 days',    // 错误日志保留 90 天
          events: '30 days',    // 事件日志保留 30 天
          debug: '7 days',      // 调试日志保留 7 天
          sessions: '180 days', // 会话日志保留 180 天
        };
        


六、思考题

思考题 1:如何排查工具调用失败?

答案


        # 1. 开启调试模式
        claude --verbose
        
        # 2. 复现问题
        # 执行出错的操作
        
        # 3. 查看日志
        tail -f ~/.claude/debug/latest
        
        # 4. 搜索相关错误
        grep -A5 "ToolError" ~/.claude/logs/errors/*
        


思考题 2:日志包含敏感信息吗?

答案


        // Claude Code 会过滤敏感信息
        const SENSITIVE_PATTERNS = [
          'password',
          'api_key',
          'secret',
          'token',
        ];
        
        function filterSensitiveData(log: Record<string, unknown>): Record<string, unknown> {
          for (const [key, value] of Object.entries(log)) {
            if (SENSITIVE_PATTERNS.some(p => key.toLowerCase().includes(p))) {
              log[key] = '[REDACTED]';
            }
          }
          return log;
        }
        


思考题 3:如何报告 Bug?

答案


        # 1. 收集日志
        claude logs export --output bug-report.zip
        
        # 2. 创建 Issue
        # 附上日志文件和复现步骤
        
        # 3. 匿名报告
        # 如果使用匿名模式,日志会自动脱敏
        


七、延伸阅读

文件核心内容
`src/utils/log.ts`日志系统核心
`src/types/logs.ts`日志类型定义


八、下节预告

下一节我们将深入 调试模式详解

- --verbose 和 --debug 的区别

- 实时调试技巧

- 常见问题诊断


*- 第一轮:□ 事实准确性*

*- 第二轮:□ 深度与洞见*

*- 第三轮:□ 可读性与价值*