14 KiB
14 KiB
日志输出系统
**本文档引用的文件** - [log.md](file://doc/core/common/log.md) - [Logger.ts](file://extensions/oops-plugin-framework/assets/core/common/log/Logger.ts) - [Hero.ts](file://assets/script/game/hero/Hero.ts) - [GameMap.ts](file://assets/script/game/map/GameMap.ts) - [Root.ts](file://extensions/oops-plugin-framework/assets/core/Root.ts) - [GameConfig.ts](file://extensions/oops-plugin-framework/assets/module/config/GameConfig.ts) - [GUI.ts](file://extensions/oops-plugin-framework/assets/core/gui/GUI.ts)目录
简介
Oops Framework 提供了一套完整而强大的日志管理系统,专门针对复杂的游戏业务逻辑进行优化。该系统不仅提供了多种颜色标识的日志输出方式,还集成了性能分析、表格化展示等高级功能,为开发者提供了全方位的调试支持。
日志系统的核心设计理念是通过颜色编码和模块分类来区分不同类型的日志信息,使开发者能够快速定位问题所在。同时,系统支持灵活的日志级别控制,可以在生产环境中安全地关闭不必要的日志输出,确保应用性能不受影响。
日志系统架构
classDiagram
class Logger {
-tags : number
+setTags(tag : LogType) : void
+trace(msg : any, color : string) : void
+logNet(msg : any, describe? : string) : void
+logModel(msg : any, describe? : string) : void
+logBusiness(msg : any, describe? : string) : void
+logView(msg : any, describe? : string) : void
+logConfig(msg : any, describe? : string) : void
+start(describe : string) : void
+end(describe : string) : void
+table(msg : any, describe? : string) : void
-isOpen(tag : LogType) : boolean
-print(tag : LogType, msg : any, color : string, describe? : string) : void
-stack(index : number) : string
-getDateString() : string
}
class LogType {
<<enumeration>>
Net : 1
Model : 2
Business : 4
View : 8
Config : 16
Trace : 32
}
Logger --> LogType : uses
图表来源
章节来源
日志输出方法详解
基础日志输出
系统提供了六种不同类型的日志输出方法,每种方法对应不同的业务模块和颜色标识:
| 方法名 | 颜色标识 | 用途描述 | 适用场景 |
|---|---|---|---|
trace() |
黑色 | 默认标准日志 | 通用调试信息 |
logConfig() |
灰色 | 配置相关日志 | 游戏配置、参数设置 |
logNet() |
橙色 | 网络通信日志 | 网络请求、数据传输 |
logModel() |
紫色 | 数据模型日志 | 数据结构、状态变更 |
logBusiness() |
蓝色 | 业务逻辑日志 | 游戏流程、规则执行 |
logView() |
绿色 | 视图界面日志 | UI交互、渲染操作 |
性能分析方法
start() 和 end() 方法
这两个方法用于性能耗时分析,通过浏览器的 console.time() 和 console.timeEnd() 实现精确的时间测量:
// 性能分析使用示例
oops.log.start("数据加载耗时");
// 执行耗时操作
const result = await loadData();
oops.log.end("数据加载耗时");
工作原理
start()方法启动计时器,记录开始时间end()方法停止计时器,计算并输出执行时间- 支持自定义描述信息,便于识别不同的性能测量点
章节来源
日志格式与结构
标准日志格式
所有日志输出都遵循统一的格式规范:
[时间戳][日志类型][文件路径->方法名]:日志内容
格式组成部分详解
| 组件 | 格式 | 示例 | 说明 |
|---|---|---|---|
| 时间戳 | [HH:mm:ss:SSS] |
[11:31:07:293] |
精确到毫秒的时间标记 |
| 日志类型 | [类型名称] |
[网络日志] |
通过颜色区分的模块标识 |
| 文件路径 | [文件名.ts] 或 [文件名.ts->方法名] |
[Hero.ts->load] |
调用位置的精确追踪 |
| 日志内容 | 具体内容 |
'英雄加载完成' |
实际的日志消息内容 |
文件路径解析机制
系统自动解析调用栈,提取文件名和方法名:
flowchart TD
A[调用堆栈] --> B[解析错误对象]
B --> C[分割堆栈行]
C --> D[提取文件信息]
D --> E{文件类型判断}
E --> |单文件| F[返回文件名]
E --> |方法调用| G[返回文件名->方法名]
F --> H[格式化输出]
G --> H
图表来源
章节来源
性能分析工具
时间测量功能
系统内置了精确的性能分析工具,支持:
基本用法
// 开始性能测量
oops.log.start("复杂算法执行");
// 执行需要测量的代码
for (let i = 0; i < 1000000; i++) {
// 复杂计算
Math.sqrt(i);
}
// 结束测量并输出结果
oops.log.end("复杂算法执行");
多重测量
// 测量多个独立的操作
oops.log.start("数据预处理");
processData();
oops.log.end("数据预处理");
oops.log.start("算法计算");
calculateResults();
oops.log.end("算法计算");
性能监控最佳实践
- 合理命名测量点:使用描述性的名称便于识别
- 避免过度测量:仅测量关键路径和瓶颈点
- 及时清理:在生产环境中移除性能测量代码
章节来源
日志表格化输出
table() 方法功能
table() 方法专门用于对象数据的表格化展示,特别适用于调试复杂的数据结构:
基本用法
// 对象数据表格化输出
const playerData = {
uid: 1001,
name: "勇者",
level: 25,
hp: 850,
mp: 300,
attributes: {
strength: 120,
agility: 95,
intelligence: 110
}
};
oops.log.table(playerData, "玩家属性详情");
输出效果
表格化输出会将对象的键值对以表格形式展示,便于快速查看和比较:
| 键名 | 值 |
|---|---|
| uid | 1001 |
| name | "勇者" |
| level | 25 |
| hp | 850 |
| mp | 300 |
| attributes | {...} |
使用场景
- 数据结构调试:查看复杂对象的内部结构
- 配置参数检查:验证配置数据的正确性
- 状态监控:跟踪游戏状态的变化
- 性能分析:对比不同条件下的数据差异
章节来源
实际开发示例
Hero.ts 中的业务日志
在英雄系统中,可以使用不同类型的日志来跟踪各种操作:
// 英雄加载过程中的日志记录
load(pos: Vec3, scale: number, uuid: number = 1001, fight_pos: number = 1) {
oops.log.logBusiness("开始加载英雄", { uuid, pos, scale });
// 加载前的预检查
oops.log.logModel("检查英雄槽位可用性");
// 资源加载
oops.log.logNet("从服务器获取英雄资源");
// 初始化英雄属性
oops.log.logBusiness("初始化英雄基础属性");
// 添加到战斗系统
oops.log.logModel("将英雄添加到战斗系统");
oops.log.logBusiness("英雄加载完成", { uuid, position: pos });
}
GameMap.ts 中的地图日志
地图系统的日志记录示例:
load() {
oops.log.logView("开始加载地图资源");
// 资源加载过程
oops.log.logNet("加载地图预制体资源");
// 地图初始化
oops.log.logModel("初始化地图数据结构");
// UI显示
oops.log.logView("创建地图显示节点");
oops.log.logBusiness("地图加载完成");
}
Root.ts 中的系统级日志
全局系统事件的日志记录:
// 游戏显示事件
game.on(Game.EVENT_SHOW, () => {
oops.log.logView("【系统】游戏前台显示");
oops.log.logBusiness("恢复游戏运行状态");
});
// 游戏隐藏事件
game.on(Game.EVENT_HIDE, () => {
oops.log.logView("【系统】游戏切到后台");
oops.log.logBusiness("暂停游戏运行状态");
});
章节来源
日志级别与模块分类
日志类型枚举
系统定义了完整的日志类型体系:
graph TD
A[LogType 枚举] --> B[Net<br/>网络层日志]
A --> C[Model<br/>数据层日志]
A --> D[Business<br/>业务层日志]
A --> E[View<br/>视图层日志]
A --> F[Config<br/>配置日志]
A --> G[Trace<br/>标准日志]
B --> B1[网络请求]
B --> B2[数据传输]
B --> B3[API调用]
C --> C1[数据结构]
C --> C2[状态变更]
C --> C3[缓存操作]
D --> D1[游戏流程]
D --> D2[规则执行]
D --> D3[事件处理]
E --> E1[UI交互]
E --> E2[渲染操作]
E --> E3[动画播放]
F --> F1[配置文件]
F --> F2[参数设置]
F --> F3[初始化数据]
G --> G1[通用调试]
G --> G2[错误提示]
G --> G3[警告信息]
图表来源
日志级别控制
setTags() 方法
通过 setTags() 方法可以控制哪些类型的日志会被输出:
// 显示所有日志类型
oops.log.setTags(
LogType.Net | LogType.Model | LogType.Business |
LogType.View | LogType.Config | LogType.Trace
);
// 只显示业务和视图日志
oops.log.setTags(LogType.Business | LogType.View);
// 关闭所有日志输出
oops.log.setTags(0);
默认行为
系统默认不显示任何日志,需要显式设置日志级别才能看到输出。
章节来源
生产环境日志控制
性能优化策略
在生产环境中,合理的日志控制对于应用性能至关重要:
1. 条件编译控制
// 开发环境启用详细日志
#if DEBUG
oops.log.setTags(
LogType.Net | LogType.Model | LogType.Business |
LogType.View | LogType.Config | LogType.Trace
);
#else
// 生产环境关闭所有日志
oops.log.setTags(0);
#endif
2. 动态日志级别调整
// 运行时动态调整日志级别
class LogManager {
static enableDebugLogs(enabled: boolean) {
if (enabled) {
oops.log.setTags(
LogType.Net | LogType.Model | LogType.Business |
LogType.View | LogType.Config | LogType.Trace
);
} else {
oops.log.setTags(0);
}
}
}
3. 模块化日志控制
// 针对不同模块设置不同的日志级别
class ModuleLogManager {
static configureNetworkLogs(enabled: boolean) {
const currentTags = oops.log.getTags();
const newTags = enabled
? currentTags | LogType.Net
: currentTags & ~LogType.Net;
oops.log.setTags(newTags);
}
}
性能影响评估
| 日志级别 | 内存占用 | CPU开销 | I/O影响 | 推荐场景 |
|---|---|---|---|---|
| 全部开启 | 高 | 高 | 高 | 开发调试 |
| 业务+视图 | 中 | 中 | 中 | 正常测试 |
| 仅错误日志 | 低 | 低 | 低 | 生产环境 |
最佳实践建议
- 开发阶段:启用全部日志以便全面调试
- 测试阶段:启用关键模块日志,减少噪音
- 生产环境:仅保留错误和关键业务日志
- 定期审查:定期检查日志输出,移除不必要的日志代码
章节来源
最佳实践指南
日志编写原则
1. 明确目的
每次写日志都应该有明确的目的:
- 调试特定问题
- 监控系统状态
- 记录重要事件
- 性能分析
2. 选择合适的日志类型
根据日志内容选择最适合的类型:
- 网络操作使用
logNet() - 数据变更使用
logModel() - 用户交互使用
logView() - 配置信息使用
logConfig()
3. 提供上下文信息
// 好的做法:提供足够的上下文
oops.log.logBusiness("玩家升级", {
playerId: player.id,
oldLevel: player.level,
newLevel: player.level + 1
});
// 避免的做法:缺乏上下文
oops.log.logBusiness("玩家升级");
日志内容组织
结构化日志
// 使用对象传递复杂信息
const logData = {
action: "skill_cast",
caster: { id: caster.id, name: caster.name },
target: { id: target.id, health: target.health },
skill: { id: skill.id, name: skill.name },
damage: calculatedDamage,
timestamp: Date.now()
};
oops.log.logBusiness("技能释放", logData);
条件日志记录
// 根据条件决定是否记录详细日志
if (DEBUG_MODE) {
oops.log.logModel("详细数据状态", gameState);
} else {
oops.log.logBusiness("游戏状态更新");
}
日志维护策略
1. 定期清理
- 移除不再需要的调试日志
- 优化重复的日志输出
- 更新过时的日志格式
2. 日志质量检查
- 确保日志信息的准确性
- 避免敏感信息泄露
- 保持日志格式的一致性
3. 性能监控
- 监控日志输出对性能的影响
- 识别高频率的日志输出点
- 优化频繁调用的日志方法
团队协作规范
日志命名约定
- 使用描述性的日志描述
- 保持术语的一致性
- 遵循团队的编码规范
日志审核流程
- 新功能开发时同步添加必要的日志
- 代码审查时检查日志的适当性
- 定期回顾和优化现有日志
通过遵循这些最佳实践,可以构建一个高效、可维护的日志系统,既满足开发调试需求,又保证生产环境的性能表现。