LinAudit 是 Linlang 的统一诊断入口。插件从 Facade 取得一个入口,再按记录的含义选择对应成员:
LinAudit audit = lin.linAudit();
| 内容 | 入口 | 用途 | |||
|---|---|---|---|---|---|
| 运行日志 | logger() | 服务状态、调试信息和普通警告 | |||
| 操作审计 | record() | 谁在何时对什么资源执行了什么操作 | |||
| 问题报告 | problem() | 稳定问题代码、故障上下文和异常原因 |
三者共用 Runtime 的输出设施,但语义和文件彼此独立。普通状态不应记录为 Problem,玩家输入错误等正常结果也不属于系统故障。
运行日志与操作审计的基本用法见下文;错误边界与代码目录分别见:Problem 与异常 ⇱和Problem 代码 ⇱。
普通状态、调试信息和不需要问题代码的警告通过 LinLogger 记录:
LinLogger logger = audit.logger();
logger.info("奖励缓存已重载:{count}", "count", rewards.size());
logger.file("数据库已落盘:{table}", "table", tableName);
logger.warn("可选资源加载失败:{file}", exception, "file", fileName);
info、warn 和 error 按租户策略写入普通日志,并可投递到控制台;file 只写普通日志文件,不向控制台输出。需要保留原因链时应使用带 Throwable 的 warn 或 error 重载,不要把堆栈转换成普通字符串。
操作审计适合保存具有业务意义、以后可能需要追溯的事件。例如管理员修改配置、玩家领取奖励或后台任务迁移数据。
简单事件可以直接记录稳定事件名和字段:
audit.record(
"config.reload",
"actor", sender.getName(),
"file", "config.yml"
);
需要完整描述事件时,使用 AuditEvent:
AuditEvent event = AuditEvent.builder("item.rename")
.actor(player.getUniqueId().toString())
.action("rename")
.resource(itemId)
.outcome(AuditOutcome.SUCCESS)
.correlationId(requestId)
.field("name", nextName)
.build();
audit.record(event);
事件名、操作名和字段名应使用稳定的机器标识,不要写入随语言变化的展示文本。correlationId 用于串联同一次请求产生的多条记录。
Runtime 只维护一个审计 Provider,但会按插件 owner 选择名称、输出目录和控制台策略。插件不需要创建日志实现,也不会与其他插件共用输出文件。
flowchart LR
Facade["LinAudit"] --> Logger["运行日志"]
Facade --> Event["操作审计"]
Facade --> Problem["问题报告"]
Logger --> Provider["Audit Provider"]
Event --> Provider
Problem --> Provider
Provider --> Tenant["按 owner 输出"]
Runtime 在插件关闭时刷新异步文件队列。确实需要等待此前记录落盘时,可以调用:
audit.flush();
讨论