Files
waf-platform/日志策略逻辑梳理与问题清单.md
2026-02-10 23:43:05 +08:00

7.4 KiB
Raw Blame History

日志策略逻辑梳理与问题清单(当前基线:E:\AI_PRODUCT\waf-platform

1. 结论摘要

  • 当前链路是 type + writeTargets 双字段共同决定行为
  • 运行时真正用于读写判断的是 writeTargetsParseWriteTargetsFromPolicy 解析结果)。
  • HTTP 与 DNS 都已接入“公用策略”下发DNS 也已支持 ClickHouse 读取。
  • 目前存在多处逻辑不一致,核心风险是:页面显示、数据库值、实际读写行为可能不同步

2. 关键入口文件

  • 类型与组合映射:EdgeCommon/pkg/serverconfigs/access_log_storages.go
  • 写入目标定义/解析:EdgeCommon/pkg/serverconfigs/access_log_write_targets.go
  • 策略创建/更新AdminEdgeAdmin/internal/web/actions/default/servers/accesslogs/createPopup.goEdgeAdmin/internal/web/actions/default/servers/accesslogs/update.go
  • 策略保存APIEdgeAPI/internal/rpc/services/service_http_access_log_policy_plus.go
  • 策略落库DAOEdgeAPI/internal/db/models/http_access_log_policy_dao.go
  • 公用策略运行时缓存:EdgeAPI/internal/accesslogs/storage_manager.go
  • HTTP 节点队列:EdgeNode/internal/nodes/http_access_log_queue.go
  • DNS 节点队列:EdgeDNS/internal/nodes/ns_access_log_queue.go
  • 节点配置下发:EdgeAPI/internal/db/models/node_dao.goEdgeAPI/internal/db/models/ns_node_dao_plus.go
  • HTTP 查询服务:EdgeAPI/internal/rpc/services/service_http_access_log.go
  • DNS 查询服务:EdgeAPI/internal/rpc/services/nameservers/service_ns_access_log.go
  • CH 查询实现:EdgeAPI/internal/clickhouse/logs_ingest_store.goEdgeAPI/internal/clickhouse/ns_logs_ingest_store.go

3. 数据模型与语义

edgeHTTPAccessLogPolicies 关键字段:

  • typefile / file_mysql / file_clickhouse / file_mysql_clickhouse / es / tcp / syslog / command
  • writeTargetsJSONfile/mysql/clickhouse 三个布尔值)
  • disableDefaultDB:停用默认数据库存储(兼容旧语义)

当前实际规则:

  1. Admin 侧根据下拉 type 生成 writeTargetsJSON
  2. API 原样落库(仅做少量历史 type 别名兼容)。
  3. 运行时使用 ParseWriteTargetsFromPolicy(writeTargets, type, disableDefaultDB) 得到最终写入目标。

4. 端到端链路(当前行为)

4.1 策略创建/更新

  • 创建与更新都会调用 ParseStorageTypeAndWriteTargets,并同时提交 typewriteTargetsJSON
  • file_clickhouse / file_mysql_clickhouse 在 UI 上隐藏了手填路径输入,依赖旧值或默认目录回退。
  • DAO 更新时,只有 writeTargetsJSON 非空才会覆盖 writeTargets 字段。

4.2 HTTP 写入链路

  • Node 侧:
    • needWriteFile = writeTargets == nil || writeTargets.NeedWriteFile()
    • needReportAPI = writeTargets == nil || writeTargets.NeedReportToAPI()
  • API 侧:
    • CreateHTTPAccessLogs 里是否写 MySQL 由 canWriteAccessLogsToDB() -> WriteMySQL() 决定。
    • 同时调用 writeAccessLogsToPolicy(),把日志再交给公用策略存储引擎处理(如 file/es/tcp/syslog/command
  • 查询侧:
    • shouldReadAccessLogsFromClickHouse() 为真且 CH 配置可用时优先读 CH。
    • CH 失败后,按 shouldReadAccessLogsFromMySQL() 回退 MySQL。

4.3 DNS 写入链路

  • DNS 节点:
    • needWriteFile = targets == nil || targets.File || targets.ClickHouse
    • needReportAPI = targets == nil || targets.MySQL
    • 即 CH-only 下 DNS 只写本地文件,不上报 API。
  • DNS API 查询:
    • 与 HTTP 一样优先 CH再按策略回退 MySQL。

4.4 节点路径更新机制

  • API 下发公用策略的 AccessLogFilePathAccessLogWriteTargets 到 HTTP/DNS 节点配置。
  • Node/DNS 收到新配置后会 SetDirByPolicyPath(...)EnsureInit/Reopen/Close,可自动切换目录。
  • 空路径时会回退到:
    • HTTPEDGE_LOG_DIR 或默认 /var/log/edge/edge-node
    • DNSEDGE_DNS_LOG_DIR 或默认 /var/log/edge/edge-dns

5. 行为矩阵(按当前代码)

  • file
    • 写文件:是
    • 写 MySQL仅当 writeTargets.mysql=true 才会写)
    • 读:优先 CH若开启否则按 MySQL 开关
  • file_mysql
    • 写文件:是
    • 写 MySQL
    • MySQL 可读;若 CH 也开则优先 CH
  • file_clickhouse
    • 写文件:是
    • 写 MySQL理论上
    • 读:优先 CH若 CH 不可用且 mysql=false则返回空
  • file_mysql_clickhouse
    • 写文件:是
    • 写 MySQL
    • 读:优先 CH失败回退 MySQL
  • es/tcp/syslog/command
    • 仍会由 writeTargets 决定是否 MySQL当前解析默认给 MySQL=true
    • 另外会通过策略引擎输出到对应目标

6. 逻辑问题清单(按优先级)

P0typewriteTargets 双真源,容易漂移

  • 页面展示与回显会参考 type,实际写读判断优先看 writeTargets
  • 一旦两者不一致会出现“UI 看起来是 ClickHouse实际还在写/读 MySQL”。

P0disableDefaultDB 在新链路中容易失效

  • WriteMySQL() 优先看 writeTargets.MySQL,只有 writeTargets 为空才回退 disableDefaultDB
  • 由于 Admin 基本总会提交 writeTargetsJSONdisableDefaultDB 常常不会真正生效。

P1HTTP 与 DNS 在 CH-only 场景上报 API 语义不一致

  • HTTPNeedReportToAPI() = MySQL || ClickHouseCH-only 仍会上报 API。
  • DNSCH-only 不上报 API仅写文件给 Fluent Bit。
  • 高并发下会带来不必要的 API 压力与行为差异。

P1file_clickhouse 可能出现空路径,策略引擎会启动失败

  • FileStorage.Start() 要求 path 非空。
  • 但 UI 在 clickhouse 组合类型隐藏路径输入,若 options.path 为空,策略引擎会报错(虽然节点本地写文件仍可回退目录工作)。

P1HTTP 可能出现“节点写文件 + API 再写文件”的重复路径

  • CreateHTTPAccessLogs 无论是否写 MySQL都会 writeAccessLogsToPolicy()
  • 公用策略若为 file*API 侧 StorageManager.createStorage() 会创建 FileStorage 并再次落文件。
  • 若目标是“仅节点写文件供 Fluent Bit 采集”,这会引入额外重复写入。

P2DNS requestId 生成算法有重复风险

  • ns_access_log_queue.gotimestamp/requestIdloop() 局部变量,每轮 tick 重置。
  • 同秒跨批次可能冲突,影响游标分页与去重。

P2UI 文案分支存在不可达条件

  • createPopup.html / update.htmlfile|file_mysql 区块内嵌了 clickhouse 条件文案分支,实际不会触发。
  • 不影响功能,但会增加理解成本。

7. 建议修复顺序

  1. 先统一单一真源(建议 API 层统一按 type 规范化并覆盖 writeTargets)。
  2. 明确 disableDefaultDBwriteTargets 的优先级,避免“配置项在 UI 可选但不生效”。
  3. 统一 HTTP/DNS 在 CH-only 的上报语义(建议都走“节点文件 + Fluent Bit”API 不再接收该流量)。
  4. 修复 file_clickhouse 空路径策略启动失败(要求路径 or 统一默认路径回填到 options
  5. 修复 DNS requestId 生成(全局原子递增或更高精度时间戳方案)。

8. 当前可用性判断

  • 系统“可运行”,但配置行为存在歧义,且在高并发下会放大成本和排障难度。
  • 若目标是稳定的高吞吐日志链路,建议优先处理 P0/P1 问题后再继续线上放量。