7.5 KiB
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 至少包含字段:ts(ISO8601 时间戳)、level、module、playerId(如有)、action、reqId(如有)。
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 可解析
- WHEN 用
cat 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 包含
operator、action、targetPlayer、args - 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 携带 reqId(uuid 或自增序列),服务端日志 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 不允许任何日志层级输出明文敏感信息