## Purpose 定义运行时日志输出、日志等级、命令行输出、文件 JSONL 输出、滚动策略和敏感信息保护。 ## Requirements ### Requirement: 运行时 logger 输出 系统 SHALL 在配置解析成功后初始化统一运行时 logger。logger SHALL 同时输出命令行 pretty 日志和文件 JSONL 日志。命令行输出、文件输出和文件滚动 SHALL 始终启用,不提供关闭开关。 #### Scenario: 默认初始化 logger - **WHEN** 配置文件未声明 `server.logging` - **THEN** 系统 SHALL 使用默认等级 `info` 初始化 console pretty 输出和 `/logs/dial.log` 文件 JSONL 输出 #### Scenario: 模块 child logger - **WHEN** bootstrap 创建 engine、server 或其他运行时模块 - **THEN** 系统 SHALL 为模块创建带 `component` 字段的 child logger #### Scenario: 配置成功后的启动失败 - **WHEN** 配置解析成功后数据库、logger、engine 或 HTTP server 初始化失败 - **THEN** 系统 SHALL 通过正式 logger 输出 `fatal` 日志并以非零状态退出 ### Requirement: 日志等级语义 系统 SHALL 支持 `trace`、`debug`、`info`、`warn`、`error` 和 `fatal` 六个日志等级。`server.logging.level` SHALL 作为全局默认等级,`server.logging.console.level` 和 `server.logging.file.level` SHALL 在省略时继承全局等级。 #### Scenario: 目的地等级继承 - **WHEN** 配置只声明 `server.logging.level: warn` - **THEN** console 和 file 输出均 SHALL 使用 `warn` 作为最低输出等级 #### Scenario: 目的地等级覆盖 - **WHEN** 配置声明 `server.logging.level: info`、`server.logging.console.level: warn` 和 `server.logging.file.level: debug` - **THEN** console SHALL 输出 `warn` 及以上日志,file SHALL 输出 `debug` 及以上日志 #### Scenario: 默认不输出 debug 检查摘要 - **WHEN** 系统使用默认 `info` 日志等级执行拨测 - **THEN** 每次检查的 debug 摘要 SHALL NOT 输出到 console 或 file ### Requirement: 文件日志滚动 系统 SHALL 对文件日志启用滚动策略。滚动 SHALL 在 `server.logging.file.rotation.size` 或 `server.logging.file.rotation.frequency` 任一条件满足时触发。`server.logging.file.rotation.maxFiles` SHALL 表示最多保留的归档文件数量,不包含当前正在写入的日志文件。 #### Scenario: 按大小滚动 - **WHEN** 当前日志文件达到配置的 `rotation.size` - **THEN** 系统 SHALL 滚动到新的日志文件继续写入 #### Scenario: 按频率滚动 - **WHEN** 当前时间达到配置的 `rotation.frequency` 周期边界 - **THEN** 系统 SHALL 滚动到新的日志文件继续写入 #### Scenario: 限制归档数量 - **WHEN** 归档日志文件数量超过 `rotation.maxFiles` - **THEN** 系统 SHALL 删除最旧的归档日志文件并保留当前正在写入的文件 ### Requirement: 日志事件内容边界 系统 SHALL 将运行日志作为运行时事件记录,而不是将每次拨测结果完整复制到日志文件。`info` SHALL 记录生命周期事件,`warn` SHALL 记录需要关注但进程可继续的异常和目标 DOWN 状态变化,`error` SHALL 记录内部异常,`debug` SHALL 记录每次检查摘要。 #### Scenario: 成功检查默认不产生日志噪音 - **WHEN** target 连续检查成功且日志等级为默认 `info` - **THEN** 系统 SHALL NOT 为每次成功检查输出 info 日志 #### Scenario: 目标首次 DOWN - **WHEN** target 没有历史状态且本次检查结果为 DOWN - **THEN** 系统 SHALL 输出 `warn` 日志,包含 targetId、targetType、durationMs 和 failure 摘要 #### Scenario: 目标恢复 UP - **WHEN** target 最近状态为 DOWN 且本次检查结果为 UP - **THEN** 系统 SHALL 输出 `info` 日志,包含 targetId、targetType 和 durationMs #### Scenario: checker rejected - **WHEN** checker 执行抛出未捕获异常导致 Promise rejected - **THEN** 系统 SHALL 输出 `error` 日志并写入 `matched: false` 的 check_result ### Requirement: 敏感信息保护 系统 SHALL 避免在日志中输出敏感配置和运行时数据。日志事件 SHALL 优先记录白名单字段,并通过日志库 redaction 对常见敏感字段进行兜底保护。 #### Scenario: HTTP 敏感 header 不输出 - **WHEN** target 配置包含 `Authorization`、`Cookie` 或 `Set-Cookie` 相关值 - **THEN** 系统 SHALL NOT 在 console 或 file 日志中输出这些原始值 #### Scenario: LLM 敏感字段不输出 - **WHEN** LLM target 配置包含 `key`、`authToken`、`prompt` 或 providerOptions - **THEN** 系统 SHALL NOT 在 console 或 file 日志中输出这些原始值 #### Scenario: 命令环境变量不输出 - **WHEN** cmd target 配置包含 `env` - **THEN** 系统 SHALL NOT 在 console 或 file 日志中输出完整环境变量表 ### Requirement: 单可执行文件兼容 运行时日志能力 SHALL 在 Bun 单可执行文件构建产物中可用。生产构建后的 executable SHALL 不依赖目标机器安装 Bun、Node.js 或 node_modules 即可输出 console 日志和滚动文件日志。 #### Scenario: standalone executable 写入文件日志 - **WHEN** 开发者运行 `bun run build` 并启动生成的 `dist/dial-server` - **THEN** executable SHALL 在配置的数据目录下创建并写入滚动文件日志