MySQL DB LogWriter / TraceStore 邊界設計
1. 文件目的
本文件承接 MySQL TaskStore command_executions 實作前確認,整理詳細診斷資料是否應由 DB LogWriter / TraceStore 承接,而不是直接塞入 MySqlTaskStore.Save(record)。
本文件只做邊界設計,不新增 table、不執行 DDL、不連真實 DB、不修改 ITaskStore / ILogWriter public method 簽章,也不修改 TaskExecutionRecord / TaskNodeExecutionRecord public constructor 或 property。
2. 目前已完成狀態
| 項目 | 狀態 | 說明 |
|---|---|---|
task_executions |
已完成 | MySqlTaskStore 已可保存任務主檔,並完成真實 DB manual-only 驗證。 |
node_executions |
已完成 | MySqlTaskStore 已可保存節點摘要,並完成真實 DB manual-only 驗證。 |
command_executions |
尚未實作 | 已完成實作前確認,結論是不宜在資料來源未固定前直接塞入 TaskStore。 |
LogEntry |
已存在 | 已包含 TaskId、NodeId、DeviceId、CommandName、RawRequestSummary、RawResponseSummary、AdapterTimeTakenMs、DataSummary、MetadataSummary、ErrorCode、Message。 |
ILogWriter |
已存在 | 目前可由 Console / File / Memory writer 接收 LogEntry。 |
WorkflowEngine |
已承接 Adapter Data | 已把 Adapter result 的 RawRequest / RawResponse / Data / Metadata 轉成 summary 寫入 LogEntry。 |
3. 核心邊界結論
MySqlTaskStore 與 DB diagnostic log 應拆開。
| 元件 | 職責 | 不應負責 |
|---|---|---|
MySqlTaskStore |
保存任務主檔與節點摘要,例如 task_executions、node_executions。 |
不保存完整診斷 log、不承擔 Raw payload 清理、不當作一般 log sink。 |
MySqlLogWriter |
將 LogEntry 安全轉成 DB trace row。 |
不改變 Workflow 結果、不取代 Console / File log、不直接執行 schema apply。 |
TaskTraceStore |
提供依 TaskId、NodeId、DeviceId、時間區間查詢 trace 的讀取介面。 | 不負責任務狀態轉換、不寫入 Workflow 核心狀態。 |
task_log_traces |
保存任務與設備命令相關診斷摘要。 | 不替代 task_executions / node_executions / command_executions。 |
4. 為什麼建議走 Log 流
command_executions 若要保存 RawRequest / RawResponse,最完整的資料目前已在 LogEntry 與 Workflow snapshot 流中。
走 LogEntry -> MySqlLogWriter -> task_log_traces 的優點:
- 不需要為了診斷欄位修改
TaskExecutionRecord/TaskNodeExecutionRecordpublic model。 - 不會讓
MySqlTaskStore.Save(record)同時承擔任務保存與大量 log sink。 - 可以獨立做 payload 遮蔽、長度限制、保留天數與查詢索引。
- DB log 寫入失敗時,可獨立處理,不必改變 Workflow 任務成功或失敗判斷。
- 未來若一個 node 執行多個 Adapter command,Log 流比 TaskStore node summary 更適合承接多筆診斷事件。
5. 建議資料流
WorkflowEngine
-> LogEntry
-> ILogWriter
-> ConsoleLogWriter
-> FileLogWriter
-> MemoryLogWriter
-> MySqlLogWriter
-> task_log_traces
TaskTraceStore
-> query task_log_traces by TaskId / NodeId / DeviceId / time range
第一版建議 MySqlLogWriter 是可選 writer,不得取代既有 Console / File / Memory writer。
6. 建議 table 定位:task_log_traces
task_log_traces 應定位為「診斷 trace table」,不是任務主檔,也不是命令執行表。
6.1 欄位草案
以下只是設計草案,尚未確認前不得建立 table。
| 欄位 | 型別 | 必填 | 來源 | 說明 |
|---|---|---|---|---|
trace_id |
varchar(64) |
是 | 寫入端產生 | Trace 主鍵,避免依賴 DB 自動編號造成測試不易比對。 |
task_id |
varchar(64) |
否 | LogEntry.TaskId |
任務識別碼。 |
node_id |
varchar(64) |
否 | LogEntry.NodeId |
Workflow 節點識別碼。 |
node_name |
varchar(128) |
否 | LogEntry.NodeName |
Workflow 節點名稱。 |
device_id |
varchar(64) |
否 | LogEntry.DeviceId |
設備識別碼。 |
command_name |
varchar(128) |
否 | LogEntry.CommandName |
Adapter 命令名稱。 |
level |
varchar(32) |
是 | LogEntry 或 writer mapping |
Log level,第一版可先以 Info / Warning / Error 表示。 |
status |
varchar(32) |
否 | LogEntry.Status |
任務、節點或命令狀態。 |
retry_count |
int |
否 | LogEntry.RetryCount |
節點 retry count。 |
time_taken_ms |
int |
否 | LogEntry.TimeTakenMs |
節點或事件耗時。 |
adapter_time_taken_ms |
int |
否 | LogEntry.AdapterTimeTakenMs |
Adapter 命令耗時。 |
error_code |
varchar(64) |
否 | LogEntry.ErrorCode |
錯誤代碼。 |
message |
varchar(255) |
否 | LogEntry.Message |
訊息摘要。 |
data_summary |
text |
否 | LogEntry.DataSummary |
Adapter Data 摘要。 |
raw_request_summary |
text |
否 | LogEntry.RawRequestSummary |
已遮蔽與截斷後的 request 摘要。 |
raw_response_summary |
text |
否 | LogEntry.RawResponseSummary |
已遮蔽與截斷後的 response 摘要。 |
metadata_summary |
text |
否 | LogEntry.MetadataSummary |
Metadata 摘要。 |
host_name |
varchar(128) |
否 | Host context | 執行主機名稱。 |
operator_id |
varchar(64) |
否 | Host context | 操作者或服務帳號。 |
app_version |
varchar(64) |
否 | Host context | 程式版本。 |
created_at |
datetime |
是 | 寫入當下 | Trace 建立時間。 |
6.2 建議索引
| Index | Columns | 用途 |
|---|---|---|
idx_task_log_traces_task_id |
task_id |
查詢指定任務完整 trace。 |
idx_task_log_traces_node_id |
node_id |
查詢特定節點 trace。 |
idx_task_log_traces_device |
device_id |
查詢設備相關 trace。 |
idx_task_log_traces_command |
command_name |
查詢命令相關 trace。 |
idx_task_log_traces_status |
status |
查詢失敗或特定狀態 trace。 |
idx_task_log_traces_error_code |
error_code |
查詢特定錯誤。 |
idx_task_log_traces_created_at |
created_at |
依時間排序與清理。 |
7. MySqlLogWriter 寫入策略
第一版建議:
MySqlLogWriter只接收已產生的LogEntry,不主動改 Workflow 狀態。- 寫入前必須經過 payload sanitizer,避免保存 password、token、connection string 或完整敏感 payload。
RawRequestSummary/RawResponseSummary只保存摘要,不保存未遮蔽完整原文。- 單筆寫入失敗時,不應讓 Workflow 任務結果由成功變失敗;但必須讓 host 或 fallback log 知道 DB log 寫入失敗。
- 第一版不做批次寫入、不做背景佇列、不做 retry worker,避免擴大到背景服務範圍。
- 第一版不自動建表,也不在 ConsoleHost 啟動時 apply schema。
8. TaskTraceStore 查詢策略
TaskTraceStore 建議作為讀取介面,不與 ITaskStore 混在一起。
建議第一版查詢能力:
| 查詢 | 用途 |
|---|---|
FindByTaskId(taskId) |
查詢單一任務完整 trace。 |
FindByNodeId(taskId, nodeId) |
查詢指定任務節點 trace。 |
FindByDeviceId(deviceId, from, to) |
查詢設備在時間區間內的 trace。 |
ListRecentErrors(limit) |
查詢最近錯誤 trace。 |
以上查詢介面若要實作,會新增 public contract,必須另做實作前確認。
9. 與 command_executions 的關係
task_log_traces 與 command_executions 不應互相取代。
| Table | 建議定位 |
|---|---|
command_executions |
給報表或任務明細查詢使用的命令執行表,欄位較固定。 |
task_log_traces |
給除錯與診斷使用的 log / trace 表,資料量較大,欄位偏診斷。 |
目前建議先做 task_log_traces 邊界設計,是因為 RawRequest / RawResponse 較接近診斷資料,不宜為了它先修改 TaskStore model。
若後續需要 command_executions,可以從 LogEntry 或 WorkflowNodeExecutionSnapshot 派生,但必須先做資料來源決策表。
10. Payload 安全規則
DB trace 不能直接保存未處理的 raw payload。
第一版 sanitizer 至少應處理:
| 規則 | 說明 |
|---|---|
| 長度限制 | request / response summary 建議限制在固定字數,例如 2,000 或 4,000 字內。 |
| 敏感字遮蔽 | password、token、secret、connection string、authorization 需遮蔽。 |
| 二進位摘要 | 若 payload 是 byte array,只保存 hex 摘要與長度,不保存完整大 payload。 |
| Null 安全 | 沒有 raw data 時保存 null,不硬塞空字串。 |
| 錯誤可讀性 | 遮蔽後仍需保留足夠資訊判斷命令、裝置與錯誤原因。 |
11. 測試策略
11.1 自動測試
| 測試 | 目的 |
|---|---|
LogEntry to trace row mapper 測試 |
確認欄位來源正確,Raw summary 不遺失。 |
| payload sanitizer 測試 | 確認敏感資訊被遮蔽,長字串會截斷。 |
| SQL generator 測試 | 確認 task_log_traces schema class 可產生 MySQL 5.6.2 DDL preview。 |
| fake gateway writer 測試 | 確認 MySqlLogWriter 寫入正確 SQL 與參數,不連真實 DB。 |
| writer failure 測試 | 確認 DB log 寫入失敗不會改變 Workflow result。 |
11.2 manual-only 真實 DB 驗證
若後續完成實作,真實 DB 驗證需另列節點,且只能在使用者明確確認後執行:
- 確認測試 DB 與 table 已準備完成。
- 明確開啟 manual-only gate。
- 寫入成功、失敗、含 Raw summary、含 ErrorCode 的 trace rows。
- 依 TaskId 查回 trace。
- 驗證 index 與 comment。
- 驗證敏感資訊未被保存。
- cleanup 僅清除本次測試前綴資料。
12. 必須停下確認的事項
以下任一項出現時,Codex 必須停下,不得自動執行:
- 新增或修改 public contract,例如
ILogWriter、ITaskStore、TaskTraceStore介面。 - 修改
TaskExecutionRecord/TaskNodeExecutionRecordpublic constructor 或 property。 - 建立
task_log_tracestable 或執行任何 DDL / ALTER。 - 對真實 DB 執行未確認的
INSERT、UPDATE、DELETE。 - 把真實 DB 測試加入一般 CI。
- 保存 password、Token、完整 connection string 或未遮蔽 RawRequest / RawResponse。
- 導入背景佇列、ServiceHost、WebApi 或正式 DB 自動 apply 流程。
- 新增或更換 MySQL 套件。
- 讓 DB log 寫入失敗直接改變 Workflow 任務成功 / 失敗結果。
13. 建議結論
建議採用「TaskStore 保存任務與節點,DB LogWriter 保存診斷 trace」的切分。
目前不要把 command_executions 或詳細 Raw 診斷資料直接塞進 MySqlTaskStore.Save(record);較安全的下一步是做「DB LogWriter / TraceStore 實作前確認」,先固定:
task_log_tracesschema class。LogEntryto trace row mapper。- payload sanitizer 規則。
- fake gateway 測試策略。
- DB log 寫入失敗時的 fallback 行為。
確認後再進入第一版實作,仍維持不自動連真實 DB、不自動建表、不修改現有 TaskStore public contract。