7.5 KiB
Raw Blame History

ADDED Requirements

Requirement: 三层日志体系

系统 MUST 实现三层日志体系L1 业务日志 / L2 审计日志 / L3 错误日志,分目录分文件输出。每层用途、保留期、格式明确分离。

层级 路径 用途 保留期
L1 业务 Logs/Business/{yyyy-MM-dd}.log RPC 入口/出口、业务操作 30 天
L2 审计 Logs/Audit/{module}/{yyyy-MM-dd}.jsonl 抽卡、付费、GM、资源变动 永久
L3 错误 Logs/Error/{yyyy-MM-dd}.log 异常、错误码、慢查询 90 天

Scenario: 日志目录分离

  • WHEN 服务端启动
  • THEN 在配置的日志根目录下自动创建 Business/ Audit/ Error/ 三个子目录
  • AND 各层日志互不混淆

Scenario: 按天滚动

  • WHEN 跨天时
  • THEN 自动创建新日期的日志文件
  • AND 超过保留期的旧文件自动清理L2 可配置归档到 OSS

Requirement: 结构化 JSON 行格式jsonl

L2 审计日志和关键 L1 业务日志 MUST 使用 jsonl 格式(每行一个独立 JSON 对象),便于 grep/jq/ELK 工具消费。MUST 至少包含字段:tsISO8601 时间戳)、levelmoduleplayerId(如有)、actionreqId(如有)。

Scenario: 抽卡审计日志

  • WHEN 玩家完成一次抽卡
  • THEN Logs/Audit/Gacha/{date}.jsonl 追加一行
  • AND 内容形如:
    {"ts":"2026-05-27T11:30:01.234","level":"INFO","module":"Gacha","playerId":1001,"action":"Draw","poolId":2,"drawType":"Multi10","costItem":2,"costCount":9,"rewards":[{"itemId":10001,"count":1,"rare":4}],"guaranteeRemain":85,"reqId":"abc123"}
    

Scenario: jq 可解析

  • WHENcat Logs/Audit/Gacha/2026-05-27.jsonl | jq '.rewards[].rare'
  • THEN 输出所有抽卡品质列表
  • AND 不出现解析错误

Requirement: RPC Handler 强制埋点

每个服务端 RPC Handler MUST 在入口和出口埋点 L1 业务日志。入口日志含playerId、actionName、关键参数出口日志含playerId、actionName、错误码、耗时毫秒

Scenario: 入口日志

  • WHEN C2G_GachaDrawHandler 被调用
  • THEN L1 日志立刻输出 [Gacha] Begin Draw playerId=1001 poolId=2 drawType=Multi10
  • AND 即使后续业务校验失败也必须有入口日志

Scenario: 出口日志

  • WHEN Handler 返回响应
  • THEN L1 日志输出 [Gacha] End Draw playerId=1001 error=0 cost=23ms
  • AND 耗时计算覆盖 Handler 全部生命周期

Scenario: 自动 Handler 包装

  • WHEN 开发者新增 Handler
  • THEN 通过基类或属性自动埋点入口/出口,不需要手写
  • AND 不允许某个 Handler 漏埋点(编译期/启动期自检)

Requirement: 关键操作必写审计日志L2

下列业务操作 MUST 写 L2 审计日志:抽卡(每次/每抽、付费、GM 操作、英雄招募/升星/觉醒、装备锻造/分解、资源大额变动(>1000 单位)、玩家登录/登出。审计日志 MUST 同步落盘(不允许丢失)。

Scenario: GM 操作审计

  • WHEN 任何 GM 命令被执行
  • THEN Logs/Audit/GM/{date}.jsonl 追加一行
  • AND 包含 operatoractiontargetPlayerargs
  • AND 即使命令失败也记录

Scenario: 资源大额变动审计

  • WHEN 玩家金币/钻石 / 高价值道具单次变动 ≥ 1000
  • THEN Logs/Audit/Resource/{date}.jsonl 追加一行
  • AND 含变动前后数量、变动原因(抽卡/购买/GM/任务等)

Scenario: 抽卡审计不可丢失

  • WHEN 服务端突然 kill -9
  • THEN 已完成的抽卡审计日志 MUST 100% 完整(同步刷盘)
  • AND 未完成的抽卡不在审计日志中

Requirement: 错误码返回必写错误日志L3

每次服务端 RPC Handler 返回非 0 错误码 MUST 同步写 L3 错误日志。MUST 含 playerId、errorCode、errorMessage、上下文参数。重复错误码 1 分钟内同 playerId 仅记录首条 + 计数(防止刷屏)。

Scenario: 错误码返回写日志

  • WHEN Handler 返回 ERR_GACHA_COST_NOT_ENOUGH
  • THEN Logs/Error/{date}.log 输出 [Gacha][ERR] playerId=1001 errorCode=30001 (ERR_GACHA_COST_NOT_ENOUGH) poolId=2 drawType=Multi10
  • AND 同时返回客户端正常的错误响应

Scenario: 重复错误降频

  • WHEN 同 playerId 同 errorCode 1 分钟内连续触发 100 次
  • THEN 仅记录首条 + 周期末计数 repeated 99 times
  • AND 避免日志爆量

Requirement: 模块标签 + reqId 全链路追踪

所有日志 MUST 携带模块标签([Hero][Bag][Gacha][Equip][DB][Login][GM][Net])。每个客户端发起的 RPC MUST 携带 reqIduuid 或自增序列),服务端日志 MUST 全程透传该 reqId。

Scenario: 单玩家行为链路追查

  • WHEN 客户端发送 C2G_GachaDraw { reqId: "abc123" }
  • THEN 服务端 Handler 收到后日志含 reqId=abc123
  • AND 后续调 BagComponentSystem.AddItems 内部日志也含该 reqId
  • AND 可通过 grep 'reqId=abc123' Logs/**/*.log 还原完整链路

Scenario: 模块标签过滤

  • WHEN 运维需要排查抽卡问题
  • THEN grep -F '[Gacha]' Logs/Business/2026-05-27.log 能精确过滤
  • AND 与其他模块日志完全隔离

Requirement: 慢操作告警

服务端 MUST 监测以下慢操作并写 L3 错误日志告警DB 查询 > 100ms、DB 写入 > 200ms、Handler 执行 > 500ms、Lua/C# Compile > 1000ms。慢操作日志 MUST 含调用栈和参数摘要。

Scenario: 慢查询告警

  • WHEN 一次 DBComponent.Query 耗时 250ms
  • THEN L3 日志输出 [DB][SLOW] Query Hero playerId=1001 duration=250ms exceeded threshold=100ms
  • AND 含调用栈(简化版)

Scenario: 慢 Handler 告警

  • WHEN 一次 RPC Handler 执行 800ms
  • THEN L3 日志输出 [Net][SLOW] C2G_GachaDraw playerId=1001 duration=800ms
  • AND 后续可在监控大盘聚合告警

Requirement: 客户端日志桥接(可选)

客户端 MUST 提供日志桥接开关:开启时,客户端 Log.Error / Log.Warning 关键日志通过专用 RPC 上报到服务端。服务端写入 Logs/Client/{date}.log,含 playerId / clientVersion / 设备信息。开关由 StartConfig 控制,默认开发期开、生产期可关。

Scenario: 客户端崩溃日志上报

  • WHEN 客户端发生 NullReferenceException
  • AND 桥接开关 ON
  • THEN 异常信息通过 C2G_ClientLogReport 上报
  • AND 服务端 Logs/Client/{date}.log 追加一行 jsonl

Scenario: 上报频率限制

  • WHEN 客户端短时间内大量错误
  • THEN 服务端 MUST 对每个 playerId 限速1 秒最多 5 条)
  • AND 超过的日志在客户端本地累计,每分钟批量上报

Requirement: 配置化与开关

日志各项行为 MUST 通过 StartConfig.Logging 或独立 LogConfig 配置日志根路径、各层级开关、滚动策略、保留期、客户端桥接开关、敏感字段脱敏列表。MUST 支持运行时通过 GM 命令 gm SetLogLevel <module> <level> 调整。

Scenario: 临时调高某模块日志级别

  • WHEN 运维执行 gm SetLogLevel Gacha Debug
  • THEN Gacha 模块日志立刻输出 Debug 级别
  • AND 持续到下次重启或再次设置

Scenario: 敏感字段脱敏

  • WHEN 配置 MaskFields = ["phone", "email", "idCard"]
  • AND 业务日志中含 phone=13800138000
  • THEN 输出为 phone=138****8000
  • AND 不允许任何日志层级输出明文敏感信息