# 任务：重构工作流日志 (基于文件缓冲的持久化方案) [已完成]

## 背景 (Context)
目前 `workflow-orchestrator-service` 通过 `publish_log` 手动向 NATS 发送日志，这种方式既不规范，也导致了“双重日志”问题（Rust 标准日志 vs 前端 NATS 日志），且无法持久化保存。

我们需要一种方案，能自动捕获 Rust 标准日志（`tracing`），将其暂存，并在工作流结束时归档到全局上下文（VGCS）中。考虑到日志可能非常长，为了避免内存溢出（OOM）和保证数据安全，我们将采用**文件系统**作为临时缓冲区，而不是内存。

## 目标 (Objectives)
1.  **清理 (Cleanup)**: 删除 `workflow-orchestrator-service` 中所有手动的 `publish_log` 和 `WorkflowEvent::TaskLog` 发送逻辑。
2.  **捕获 (Capture)**: 实现一个自定义的 `tracing` Layer，能够识别当前的 `request_id`，并将日志实时追加写入到磁盘上的临时文件中。
3.  **持久化 (Persistence)**: 当工作流结束（无论成功或失败）时，读取对应的临时日志文件，将其存入 VGCS 仓库（`workflow.log`），然后清理临时文件。

## 实施方案 (Implementation Plan)

### 1. 日志管理器 (`LogBufferManager`)
创建一个新的结构体 `LogBufferManager`，用于管理临时日志文件。

*   **目录**: 在服务根目录下创建 `temp_logs/` 目录。
*   **路径策略**: 每个请求对应一个文件，例如 `temp_logs/{request_id}.log`。
*   **功能**:
    *   `append(request_id, message)`: 以追加模式打开（或创建）文件，写入日志行。为了性能，可以考虑持有活跃文件的句柄缓存（`DashMap<String, File>`），或者简单地每次打开（OS层面对追加写的缓存通常已经很好）。考虑到并发量不大，**每次 Open 追加**是最稳妥且无状态的，不容易出 Bug。
    *   `finalize(request_id)`: 读取完整文件内容，返回 `String` 或 `Vec<u8>`，然后**删除**该文件。

### 2. 自定义 Tracing Layer (`FileRequestLogLayer`)
在 `workflow-orchestrator-service` 中新建 `logging` 模块。

*   实现 `tracing_subscriber::Layer`。
*   **逻辑 (`on_event`)**:
    1.  从 Span 的 Extensions 中尝试获取 `request_id` (或者从 event 的字段中获取)。
    2.  如果找到了 `request_id`：
        *   格式化日志信息 (e.g., `[2025-11-30T10:00:00Z INFO] Message...`).
        *   调用 `LogBufferManager::append(request_id, line)`.

### 3. 更新 `AppState` 与 `main.rs`
*   在 `AppState` 中加入 `pub log_manager: Arc<LogBufferManager>`。
*   在 `main.rs` 中初始化 `LogBufferManager` (确保 `temp_logs` 目录存在)。
*   配置 `tracing-subscriber`，将 `FileRequestLogLayer` 注册进去。注意：Layer 需要能访问到 `LogBufferManager`（可以通过全局静态变量或者在 Layer 构造时传入 Arc）。

### 4. 重构 `WorkflowEngine` (`workflow.rs`)
*   **移除旧代码**: 删除所有 `publish_log` 方法及其调用。
*   **上下文传递**: 确保所有处理逻辑都在带有 `request_id` 的 Span 下运行。
    *   例如: `let _span = tracing::info_span!("workflow", request_id = %req_id).entered();`
    *   或者使用 `#[tracing::instrument(fields(request_id = %cmd.request_id))]`。
*   **归档逻辑**:
    *   在 `try_finish_workflow` (或处理完成/失败的地方)：
    *   调用 `self.state.log_manager.finalize(req_id)` 获取完整日志。
    *   使用 `self.state.vgcs` 将日志内容写入 `workflow.log` (或 `_execution.log`)。
    *   提交到 VGCS。

## 预期结果
*   **稳定性**: 即使日志有几百 MB，也不会占用服务内存，只会占用磁盘空间。
*   **隔离性**: 不同 Request 的日志写入不同的文件，互不干扰，支持高并发。
*   **可观测性**: 未来通过 History API 可以查看到完整的、包含系统级信息的执行日志。

## 约束与风险
*   **磁盘空间**: 需定期清理 `temp_logs` 中可能因服务崩溃而残留的僵尸文件（可以在服务启动时清理，或者由 Cron 处理）。目前先在服务启动时打印警告或简单清理。
*   **性能**: 频繁的文件打开/关闭（Append模式）在 SSD 上通常不是问题，但如果是极高频日志（每秒数千条）可能会有开销。鉴于我们的场景是分析任务，频率可控。

