1520 lines
37 KiB
Markdown
1520 lines
37 KiB
Markdown
# 工具模块详解
|
||
|
||
## 📋 文档概述
|
||
|
||
本文档详细说明进贤麻将的工具模块系统,包括:
|
||
- **Logger.js** - 日志管理器
|
||
- **ErrorHandler.js** - 错误处理器
|
||
- **shared/utils** - 共享工具类
|
||
- 工具模块的使用方法和最佳实践
|
||
|
||
**文档目标**:帮助开发者正确使用日志系统和错误处理机制,提升代码质量和可维护性。
|
||
|
||
---
|
||
|
||
## 🎯 工具模块架构
|
||
|
||
### 系统组成
|
||
|
||
```
|
||
工具模块系统
|
||
├── utils/ # 子游戏专用工具
|
||
│ ├── Logger.js # 日志管理器
|
||
│ └── ErrorHandler.js # 错误处理器
|
||
│
|
||
└── shared/utils/ # 前后端共享工具
|
||
├── ArrayUtils.js # 数组操作工具
|
||
├── CardSourceInfoHelper.js # 牌源信息辅助
|
||
├── GameContextHelper.js # 游戏上下文辅助
|
||
├── GameStateHelper.js # 游戏状态辅助
|
||
├── MahjongCardUniqueId.js # 麻将牌唯一ID
|
||
└── RoomConfigUtils.js # 房间配置工具
|
||
```
|
||
|
||
### 设计原则
|
||
|
||
1. **分离关注点**:日志和错误处理分开管理
|
||
2. **ES5兼容**:兼容浏览器和Node.js环境
|
||
3. **统一接口**:提供统一的API调用方式
|
||
4. **性能优化**:最小化性能开销
|
||
5. **易于使用**:简单直观的API设计
|
||
|
||
---
|
||
|
||
## 📝 Logger.js - 日志管理器
|
||
|
||
### 核心功能
|
||
|
||
**文件位置**:`server/games2/jinxianmahjong/utils/Logger.js`
|
||
**版本**:v1.0.0
|
||
**总行数**:606行
|
||
|
||
Logger提供了完整的日志管理功能:
|
||
- ✅ 6级日志系统(TRACE/DEBUG/INFO/WARN/ERROR/FATAL)
|
||
- ✅ 日志格式化和美化输出
|
||
- ✅ 日志历史记录和查询
|
||
- ✅ 日志统计分析
|
||
- ✅ 性能计时功能
|
||
- ✅ 分组日志输出
|
||
- ✅ 控制台颜色支持
|
||
|
||
### 日志级别定义
|
||
|
||
```javascript
|
||
LOG_LEVELS: {
|
||
TRACE: 0, // 最详细的信息,用于跟踪程序执行
|
||
DEBUG: 1, // 调试信息,开发时使用
|
||
INFO: 2, // 一般信息,记录程序运行状态
|
||
WARN: 3, // 警告信息,可能的问题
|
||
ERROR: 4, // 错误信息,程序运行错误
|
||
FATAL: 5 // 致命错误,程序无法继续运行
|
||
}
|
||
```
|
||
|
||
**级别控制**:只有 `>= currentLevel` 的日志才会输出
|
||
|
||
**颜色编码**:
|
||
| 级别 | 颜色 | 说明 |
|
||
|------|------|------|
|
||
| TRACE | 白色 | 详细跟踪信息 |
|
||
| DEBUG | 青色 | 开发调试信息 |
|
||
| INFO | 绿色 | 正常运行信息 |
|
||
| WARN | 黄色 | 警告提示信息 |
|
||
| ERROR | 红色 | 错误异常信息 |
|
||
| FATAL | 紫色 | 致命错误信息 |
|
||
|
||
### 配置参数
|
||
|
||
```javascript
|
||
config: {
|
||
// 当前日志级别
|
||
currentLevel: 1, // 默认DEBUG级别
|
||
|
||
// 输出设置
|
||
enableConsole: true, // 启用控制台输出
|
||
enableColors: true, // 启用颜色(如果支持)
|
||
enableTimestamp: true, // 启用时间戳
|
||
enableModuleName: true, // 启用模块名
|
||
enableStackTrace: false, // 启用堆栈跟踪(ERROR级别以上)
|
||
|
||
// 格式设置
|
||
timestampFormat: 'ISO', // 时间戳格式: 'ISO', 'LOCAL', 'TIMESTAMP'
|
||
moduleName: 'JinXianMahjong', // 模块名
|
||
|
||
// 性能设置
|
||
maxLogHistory: 1000, // 最大日志历史记录数
|
||
flushInterval: 0 // 刷新间隔(毫秒,0表示立即输出)
|
||
}
|
||
```
|
||
|
||
### 核心API
|
||
|
||
#### 1. 设置日志级别
|
||
|
||
```javascript
|
||
/**
|
||
* 设置日志级别
|
||
* @param {number|string} level - 日志级别(数字或字符串)
|
||
*/
|
||
Logger.setLevel(level)
|
||
|
||
// 使用示例
|
||
Logger.setLevel('DEBUG'); // 使用字符串
|
||
Logger.setLevel(1); // 使用数字
|
||
Logger.setLevel('INFO'); // 只输出INFO及以上级别
|
||
```
|
||
|
||
#### 2. 记录日志
|
||
|
||
**基础日志方法**:
|
||
|
||
```javascript
|
||
/**
|
||
* 记录日志
|
||
* @param {string} tag - 标签(模块/功能名称)
|
||
* @param {string} message - 日志消息
|
||
* @param {Object} data - 附加数据(可选)
|
||
*/
|
||
Logger.trace(tag, message, data)
|
||
Logger.debug(tag, message, data)
|
||
Logger.info(tag, message, data)
|
||
Logger.warn(tag, message, data)
|
||
Logger.error(tag, message, data)
|
||
Logger.fatal(tag, message, data)
|
||
```
|
||
|
||
**使用示例**:
|
||
|
||
```javascript
|
||
// 基础日志
|
||
Logger.info('GameController', '游戏开始');
|
||
|
||
// 带附加数据的日志
|
||
Logger.debug('MahjongService', '发牌完成', {
|
||
playerCount: 4,
|
||
tilesPerPlayer: 13
|
||
});
|
||
|
||
// 警告日志
|
||
Logger.warn('OperationManager', '玩家操作超时', {
|
||
playerId: 'player001',
|
||
operation: 'discard',
|
||
timeout: 15000
|
||
});
|
||
|
||
// 错误日志
|
||
Logger.error('RpcHandler', 'RPC调用失败', {
|
||
method: 'player_discard',
|
||
errorCode: 2001,
|
||
error: error.message
|
||
});
|
||
|
||
// 致命错误
|
||
Logger.fatal('System', '系统初始化失败', {
|
||
reason: '依赖模块加载失败'
|
||
});
|
||
```
|
||
|
||
#### 3. 分组日志
|
||
|
||
```javascript
|
||
/**
|
||
* 分组日志(用于组织相关日志)
|
||
*/
|
||
Logger.group(groupName) // 开始分组
|
||
Logger.groupEnd() // 结束分组
|
||
Logger.groupCollapsed(groupName) // 开始折叠分组(默认折叠)
|
||
|
||
// 使用示例
|
||
Logger.group('游戏初始化');
|
||
Logger.info('Init', '加载配置');
|
||
Logger.info('Init', '创建游戏状态');
|
||
Logger.info('Init', '初始化牌墙');
|
||
Logger.groupEnd();
|
||
```
|
||
|
||
#### 4. 性能计时
|
||
|
||
```javascript
|
||
/**
|
||
* 性能计时
|
||
*/
|
||
Logger.time(label) // 开始计时
|
||
Logger.timeEnd(label) // 结束计时并输出
|
||
|
||
// 使用示例
|
||
Logger.time('胡牌检测');
|
||
var result = WinDetectionFactory.detectWin(handTiles, jingInfo);
|
||
Logger.timeEnd('胡牌检测'); // 输出: 胡牌检测: 3.142ms
|
||
```
|
||
|
||
#### 5. 表格输出
|
||
|
||
```javascript
|
||
/**
|
||
* 表格输出(用于输出结构化数据)
|
||
* @param {Array|Object} data - 表格数据
|
||
*/
|
||
Logger.table(data)
|
||
|
||
// 使用示例
|
||
var players = [
|
||
{ id: 'p1', name: '玩家1', score: 100 },
|
||
{ id: 'p2', name: '玩家2', score: 50 },
|
||
{ id: 'p3', name: '玩家3', score: -30 },
|
||
{ id: 'p4', name: '玩家4', score: -20 }
|
||
];
|
||
Logger.table(players);
|
||
```
|
||
|
||
#### 6. 日志历史
|
||
|
||
```javascript
|
||
/**
|
||
* 获取日志历史
|
||
* @param {number} limit - 返回数量限制(可选)
|
||
* @param {number} level - 过滤日志级别(可选)
|
||
* @returns {Array} 日志历史数组
|
||
*/
|
||
Logger.getHistory(limit, level)
|
||
|
||
// 使用示例
|
||
var allLogs = Logger.getHistory(); // 获取所有日志
|
||
var last100 = Logger.getHistory(100); // 获取最近100条
|
||
var errors = Logger.getHistory(null, Logger.LOG_LEVELS.ERROR); // 只获取错误日志
|
||
```
|
||
|
||
#### 7. 清空历史
|
||
|
||
```javascript
|
||
/**
|
||
* 清空日志历史
|
||
*/
|
||
Logger.clearHistory()
|
||
```
|
||
|
||
#### 8. 日志统计
|
||
|
||
```javascript
|
||
/**
|
||
* 获取日志统计信息
|
||
* @returns {Object} 统计对象
|
||
*/
|
||
Logger.getStatistics()
|
||
|
||
// 返回示例
|
||
{
|
||
total: 1523, // 总日志数
|
||
byLevel: { // 按级别统计
|
||
0: 234, // TRACE
|
||
1: 567, // DEBUG
|
||
2: 456, // INFO
|
||
3: 123, // WARN
|
||
4: 89, // ERROR
|
||
5: 54 // FATAL
|
||
},
|
||
startTime: 1697376000000, // 统计开始时间
|
||
duration: 3600000, // 运行时长(毫秒)
|
||
rate: 0.42 // 日志频率(条/秒)
|
||
}
|
||
```
|
||
|
||
#### 9. 重置统计
|
||
|
||
```javascript
|
||
/**
|
||
* 重置日志统计
|
||
*/
|
||
Logger.resetStatistics()
|
||
```
|
||
|
||
#### 10. 配置管理
|
||
|
||
```javascript
|
||
/**
|
||
* 配置Logger
|
||
* @param {Object} options - 配置选项
|
||
*/
|
||
Logger.configure(options)
|
||
|
||
// 使用示例
|
||
Logger.configure({
|
||
currentLevel: Logger.LOG_LEVELS.INFO, // 设置为INFO级别
|
||
enableTimestamp: true, // 启用时间戳
|
||
enableColors: true, // 启用颜色
|
||
timestampFormat: 'ISO', // 使用ISO格式
|
||
maxLogHistory: 500 // 最多保存500条历史
|
||
});
|
||
```
|
||
|
||
### 日志格式
|
||
|
||
**标准格式**:
|
||
```
|
||
[时间戳] [级别] [模块名:标签] 消息内容
|
||
```
|
||
|
||
**输出示例**:
|
||
```
|
||
[2025-10-15T10:30:45.123Z] [INFO] [JinXianMahjong:GameController] 游戏开始
|
||
[2025-10-15T10:30:45.456Z] [DEBUG] [JinXianMahjong:MahjongService] 发牌完成 { playerCount: 4, tilesPerPlayer: 13 }
|
||
[2025-10-15T10:30:46.789Z] [WARN] [JinXianMahjong:OperationManager] 玩家操作超时 { playerId: 'player001', timeout: 15000 }
|
||
[2025-10-15T10:30:47.012Z] [ERROR] [JinXianMahjong:RpcHandler] RPC调用失败 { method: 'player_discard', errorCode: 2001 }
|
||
```
|
||
|
||
### 实际使用场景
|
||
|
||
#### 场景1:游戏流程日志
|
||
|
||
```javascript
|
||
// GameController.js
|
||
|
||
GameController.prototype.startGame = function() {
|
||
Logger.info('GameController', '======= 开始新游戏 =======');
|
||
|
||
Logger.group('游戏初始化');
|
||
Logger.debug('GameController', '玩家数量:', this.players.length);
|
||
Logger.debug('GameController', '房间配置:', this.roomtype);
|
||
|
||
try {
|
||
// 初始化游戏状态
|
||
Logger.time('初始化游戏状态');
|
||
this.gameState = GameStateManager.createGameState(
|
||
this.roomcode,
|
||
this.roomtype,
|
||
this.getPlayerIds()
|
||
);
|
||
Logger.timeEnd('初始化游戏状态');
|
||
|
||
Logger.info('GameController', '游戏状态创建成功');
|
||
|
||
// 初始化牌墙
|
||
Logger.time('初始化牌墙');
|
||
this.mahjongWall = MahjongWall.initialize(this.gameState);
|
||
Logger.timeEnd('初始化牌墙');
|
||
|
||
Logger.info('GameController', '牌墙初始化完成');
|
||
|
||
// 发牌
|
||
Logger.time('发牌');
|
||
this.dealTiles();
|
||
Logger.timeEnd('发牌');
|
||
|
||
Logger.info('GameController', '发牌完成');
|
||
|
||
} catch (error) {
|
||
Logger.error('GameController', '游戏初始化失败', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
throw error;
|
||
}
|
||
|
||
Logger.groupEnd();
|
||
Logger.info('GameController', '======= 游戏初始化完成 =======');
|
||
};
|
||
```
|
||
|
||
#### 场景2:调试日志
|
||
|
||
```javascript
|
||
// MahjongGameService.js
|
||
|
||
MahjongGameService.prototype.checkWinCondition = function(playerHand, gameState) {
|
||
Logger.debug('MahjongGameService', '开始检查胡牌条件', {
|
||
playerId: playerHand.playerId,
|
||
handSize: playerHand.tiles.length
|
||
});
|
||
|
||
var rules = gameState.rules;
|
||
Logger.trace('MahjongGameService', '规则配置', {
|
||
useJing: rules.gameRules.useJing,
|
||
minFan: rules.winConditions.minFan
|
||
});
|
||
|
||
// 胡牌检测
|
||
Logger.time('胡牌检测');
|
||
var winResult = WinDetectionFactory.detectWin(playerHand, gameState.jingInfo);
|
||
Logger.timeEnd('胡牌检测');
|
||
|
||
Logger.debug('MahjongGameService', '胡牌检测结果', {
|
||
canWin: winResult.canWin,
|
||
patterns: winResult.patterns
|
||
});
|
||
|
||
if (!winResult.canWin) {
|
||
Logger.debug('MahjongGameService', '不满足胡牌条件');
|
||
return { canWin: false };
|
||
}
|
||
|
||
// 检查分数
|
||
var score = ScoreCalculation.calculateWinScore(
|
||
winResult.patterns,
|
||
gameState.jingInfo,
|
||
gameState
|
||
);
|
||
|
||
Logger.debug('MahjongGameService', '计算得分', {
|
||
totalScore: score.totalScore,
|
||
minFan: rules.winConditions.minFan
|
||
});
|
||
|
||
if (score.totalScore < rules.winConditions.minFan) {
|
||
Logger.warn('MahjongGameService', '未达到起胡分数要求', {
|
||
currentScore: score.totalScore,
|
||
required: rules.winConditions.minFan
|
||
});
|
||
return {
|
||
canWin: false,
|
||
reason: '未达到起胡分数要求(需' + rules.winConditions.minFan + '分)'
|
||
};
|
||
}
|
||
|
||
Logger.info('MahjongGameService', '胡牌条件满足', {
|
||
playerId: playerHand.playerId,
|
||
score: score.totalScore
|
||
});
|
||
|
||
return {
|
||
canWin: true,
|
||
patterns: winResult.patterns,
|
||
score: score
|
||
};
|
||
};
|
||
```
|
||
|
||
#### 场景3:错误日志
|
||
|
||
```javascript
|
||
// RpcHandler.js
|
||
|
||
RpcHandler.prototype.handleRequest = function(pack, room, callback) {
|
||
var method = pack.cmd;
|
||
|
||
Logger.info('RpcHandler', 'RPC请求', {
|
||
method: method,
|
||
playerId: pack.playerid
|
||
});
|
||
|
||
try {
|
||
// 验证玩家
|
||
if (!this._validatePlayer(pack.playerid, room)) {
|
||
Logger.warn('RpcHandler', '玩家验证失败', {
|
||
playerId: pack.playerid,
|
||
roomcode: room.roomcode
|
||
});
|
||
return callback({ error: '玩家不存在' });
|
||
}
|
||
|
||
// 执行RPC方法
|
||
var result = this._executeMethod(method, pack, room);
|
||
|
||
Logger.debug('RpcHandler', 'RPC执行成功', {
|
||
method: method,
|
||
result: result
|
||
});
|
||
|
||
callback(result);
|
||
|
||
} catch (error) {
|
||
Logger.error('RpcHandler', 'RPC执行失败', {
|
||
method: method,
|
||
playerId: pack.playerid,
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
|
||
callback({ error: '处理请求失败' });
|
||
}
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ ErrorHandler.js - 错误处理器
|
||
|
||
### 核心功能
|
||
|
||
**文件位置**:`server/games2/jinxianmahjong/utils/ErrorHandler.js`
|
||
**版本**:v1.0.0
|
||
**总行数**:659行
|
||
|
||
ErrorHandler提供了完整的错误管理功能:
|
||
- ✅ 标准化错误代码系统
|
||
- ✅ 错误分类和级别管理
|
||
- ✅ 错误创建和格式化
|
||
- ✅ 错误统计和追踪
|
||
- ✅ 安全执行包装
|
||
- ✅ 错误恢复策略
|
||
|
||
### 错误代码范围
|
||
|
||
```javascript
|
||
ERROR_CODE_RANGES: {
|
||
CLIENT_START: 1000, // 客户端/接口错误
|
||
CLIENT_END: 1999,
|
||
|
||
VALIDATION_START: 2000, // 数据验证错误
|
||
VALIDATION_END: 2999,
|
||
|
||
GAME_LOGIC_START: 3000, // 游戏逻辑错误
|
||
GAME_LOGIC_END: 3999,
|
||
|
||
BUSINESS_START: 4000, // 业务逻辑错误
|
||
BUSINESS_END: 4999,
|
||
|
||
NETWORK_START: 5000, // 网络通信错误
|
||
NETWORK_END: 5999,
|
||
|
||
SYSTEM_START: 9000 // 系统错误
|
||
}
|
||
```
|
||
|
||
### 错误代码定义
|
||
|
||
#### 1. 框架接口错误(1000-1999)
|
||
|
||
```javascript
|
||
INTERFACE_INVALID_PARAMS: 1001, // 接口参数无效
|
||
INTERFACE_ROOM_NOT_FOUND: 1002, // 房间不存在
|
||
INTERFACE_PLAYER_NOT_FOUND: 1003, // 玩家不存在
|
||
INTERFACE_CALLBACK_MISSING: 1004, // 回调函数缺失
|
||
INTERFACE_METHOD_NOT_IMPLEMENTED: 1005, // 接口方法未实现
|
||
INTERFACE_TIMEOUT: 1006, // 接口调用超时
|
||
INTERFACE_UNAUTHORIZED: 1007, // 接口未授权
|
||
INTERFACE_RATE_LIMITED: 1008, // 接口调用频率限制
|
||
```
|
||
|
||
#### 2. 游戏逻辑错误(2000-2999)
|
||
|
||
```javascript
|
||
GAME_INVALID_ACTION: 2001, // 无效的游戏操作
|
||
GAME_WRONG_PHASE: 2002, // 游戏阶段错误
|
||
GAME_PLAYER_LIMIT: 2003, // 玩家数量限制
|
||
GAME_ROOM_FULL: 2004, // 房间已满
|
||
GAME_ALREADY_STARTED: 2005, // 游戏已开始
|
||
GAME_NOT_STARTED: 2006, // 游戏未开始
|
||
GAME_INVALID_CARD: 2007, // 无效牌张
|
||
GAME_INVALID_OPERATION: 2008, // 无效操作
|
||
GAME_TIMEOUT: 2009, // 游戏操作超时
|
||
GAME_INSUFFICIENT_PLAYERS: 2010, // 玩家不足
|
||
```
|
||
|
||
#### 3. 数据验证错误(3000-3999)
|
||
|
||
```javascript
|
||
VALIDATION_ROOMTYPE: 3001, // RoomType格式错误
|
||
VALIDATION_CARD_DATA: 3002, // 牌张数据无效
|
||
VALIDATION_PLAYER_DATA: 3003, // 玩家数据无效
|
||
VALIDATION_ROOM_DATA: 3004, // 房间数据无效
|
||
VALIDATION_GAME_STATE: 3005, // 游戏状态无效
|
||
VALIDATION_CONFIG: 3006, // 配置数据无效
|
||
VALIDATION_MISSING_REQUIRED: 3007, // 缺少必需字段
|
||
VALIDATION_TYPE_MISMATCH: 3008, // 数据类型不匹配
|
||
```
|
||
|
||
#### 4. 业务逻辑错误(4000-4999)
|
||
|
||
```javascript
|
||
BUSINESS_ROOM_CLOSED: 4001, // 房间已关闭
|
||
BUSINESS_PLAYER_OFFLINE: 4002, // 玩家离线
|
||
BUSINESS_INSUFFICIENT_PERMISSION: 4003, // 权限不足
|
||
BUSINESS_DUPLICATE_ACTION: 4004, // 重复操作
|
||
BUSINESS_INVALID_STATE: 4005, // 无效状态
|
||
BUSINESS_RESOURCE_UNAVAILABLE: 4006, // 资源不可用
|
||
```
|
||
|
||
#### 5. 网络通信错误(5000-5999)
|
||
|
||
```javascript
|
||
NETWORK_CONNECTION_LOST: 5001, // 连接丢失
|
||
NETWORK_TIMEOUT: 5002, // 网络超时
|
||
NETWORK_INVALID_RESPONSE: 5003, // 无效响应
|
||
NETWORK_SERVER_ERROR: 5004, // 服务器错误
|
||
```
|
||
|
||
#### 6. 系统错误(9000-9999)
|
||
|
||
```javascript
|
||
SYSTEM_UNKNOWN: 9001, // 未知系统错误
|
||
SYSTEM_TIMEOUT: 9002, // 系统超时
|
||
SYSTEM_MEMORY_ERROR: 9003, // 内存错误
|
||
SYSTEM_CONFIGURATION_ERROR: 9004, // 配置错误
|
||
SYSTEM_INITIALIZATION_FAILED: 9005, // 初始化失败
|
||
SYSTEM_DEPENDENCY_ERROR: 9006 // 依赖错误
|
||
```
|
||
|
||
### 错误严重级别
|
||
|
||
```javascript
|
||
ERROR_LEVELS: {
|
||
FATAL: 'FATAL', // 致命错误,系统无法继续运行
|
||
ERROR: 'ERROR', // 错误,功能无法正常执行
|
||
WARN: 'WARN', // 警告,可能影响功能
|
||
INFO: 'INFO' // 信息,仅用于记录
|
||
}
|
||
```
|
||
|
||
### 核心API
|
||
|
||
#### 1. 创建错误对象
|
||
|
||
```javascript
|
||
/**
|
||
* 创建错误对象
|
||
* @param {number} code - 错误代码
|
||
* @param {string} message - 自定义错误消息(可选)
|
||
* @param {Object} context - 错误上下文信息(可选)
|
||
* @param {string} level - 错误级别(可选)
|
||
* @returns {Object} 标准化错误对象
|
||
*/
|
||
ErrorHandler.createError(code, message, context, level)
|
||
|
||
// 使用示例
|
||
var error = ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_INVALID_ACTION,
|
||
'当前阶段不允许出牌',
|
||
{
|
||
playerId: 'player001',
|
||
currentPhase: 'WAITING',
|
||
expectedPhase: 'PLAYING'
|
||
}
|
||
);
|
||
|
||
// 返回的错误对象
|
||
{
|
||
code: 2001,
|
||
message: '当前阶段不允许出牌',
|
||
level: 'ERROR',
|
||
timestamp: 1697376000000,
|
||
context: {
|
||
playerId: 'player001',
|
||
currentPhase: 'WAITING',
|
||
expectedPhase: 'PLAYING'
|
||
},
|
||
stack: '...堆栈信息...',
|
||
module: 'JinXianMahjong',
|
||
version: '1.0.0',
|
||
category: 'GAME_LOGIC'
|
||
}
|
||
```
|
||
|
||
#### 2. 安全执行函数
|
||
|
||
```javascript
|
||
/**
|
||
* 包装函数执行,自动捕获错误
|
||
* @param {Function} func - 要执行的函数
|
||
* @param {Object} context - 执行上下文
|
||
* @param {Array} args - 函数参数
|
||
* @returns {Object} 执行结果 {success: boolean, result: any, error: Object}
|
||
*/
|
||
ErrorHandler.safeExecute(func, context, args)
|
||
|
||
// 使用示例
|
||
var result = ErrorHandler.safeExecute(
|
||
function() {
|
||
return this.performRiskyOperation();
|
||
},
|
||
gameController,
|
||
[]
|
||
);
|
||
|
||
if (result.success) {
|
||
console.log('操作成功:', result.result);
|
||
} else {
|
||
console.error('操作失败:', result.error);
|
||
}
|
||
```
|
||
|
||
#### 3. 格式化错误信息
|
||
|
||
```javascript
|
||
/**
|
||
* 格式化错误信息用于显示
|
||
* @param {Object} error - 错误对象
|
||
* @returns {string} 格式化后的错误信息
|
||
*/
|
||
ErrorHandler.formatErrorMessage(error)
|
||
|
||
// 使用示例
|
||
var error = ErrorHandler.createError(2001, '无效操作');
|
||
var message = ErrorHandler.formatErrorMessage(error);
|
||
// 输出: "[ERROR:2001] 无效操作"
|
||
```
|
||
|
||
#### 4. 错误恢复
|
||
|
||
```javascript
|
||
/**
|
||
* 尝试从错误中恢复
|
||
* @param {Object} error - 错误对象
|
||
* @param {Function} recoveryFunc - 恢复函数
|
||
* @returns {boolean} 是否成功恢复
|
||
*/
|
||
ErrorHandler.tryRecover(error, recoveryFunc)
|
||
|
||
// 使用示例
|
||
var recovered = ErrorHandler.tryRecover(error, function() {
|
||
// 尝试恢复逻辑
|
||
return game.resetToLastValidState();
|
||
});
|
||
|
||
if (recovered) {
|
||
Logger.info('ErrorHandler', '已成功从错误中恢复');
|
||
} else {
|
||
Logger.error('ErrorHandler', '无法从错误中恢复');
|
||
}
|
||
```
|
||
|
||
#### 5. 错误统计
|
||
|
||
```javascript
|
||
/**
|
||
* 获取错误统计信息
|
||
* @returns {Object} 统计对象
|
||
*/
|
||
ErrorHandler.getStatistics()
|
||
|
||
// 返回示例
|
||
{
|
||
total: 45,
|
||
byCode: {
|
||
2001: 12,
|
||
3001: 8,
|
||
4001: 5
|
||
},
|
||
byLevel: {
|
||
FATAL: 1,
|
||
ERROR: 25,
|
||
WARN: 15,
|
||
INFO: 4
|
||
},
|
||
recent: [...] // 最近100条错误
|
||
}
|
||
```
|
||
|
||
### 实际使用场景
|
||
|
||
#### 场景1:接口参数验证
|
||
|
||
```javascript
|
||
// export.js - Export.makewar()
|
||
|
||
export.makewar = function(room, roomtype) {
|
||
try {
|
||
// 参数验证
|
||
if (!room) {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.INTERFACE_INVALID_PARAMS,
|
||
'room参数不能为空',
|
||
{ functionName: 'makewar' }
|
||
);
|
||
}
|
||
|
||
if (!roomtype) {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.INTERFACE_INVALID_PARAMS,
|
||
'roomtype参数不能为空',
|
||
{ functionName: 'makewar' }
|
||
);
|
||
}
|
||
|
||
// 验证roomtype格式
|
||
var validation = RoomConfigUtils.validate(roomtype);
|
||
if (!validation.isValid) {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.VALIDATION_ROOMTYPE,
|
||
'roomtype格式错误: ' + validation.errors.join(', '),
|
||
{ roomtype: roomtype, errors: validation.errors }
|
||
);
|
||
}
|
||
|
||
// 创建游戏
|
||
Logger.info('Export', '开始创建游戏');
|
||
var gameState = GameStateManager.createGameState(
|
||
room.roomcode,
|
||
roomtype,
|
||
room.getPlayerIds()
|
||
);
|
||
|
||
return { success: true, gameState: gameState };
|
||
|
||
} catch (error) {
|
||
Logger.error('Export', 'makewar失败', {
|
||
error: error.message,
|
||
code: error.code
|
||
});
|
||
|
||
return {
|
||
success: false,
|
||
error: ErrorHandler.formatErrorMessage(error)
|
||
};
|
||
}
|
||
};
|
||
```
|
||
|
||
#### 场景2:游戏逻辑错误处理
|
||
|
||
```javascript
|
||
// OperationManager.js
|
||
|
||
OperationManager.prototype.validateDiscard = function(playerId, tileCode) {
|
||
// 检查游戏是否开始
|
||
if (this.gameState.phase !== 'PLAYING') {
|
||
return ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_WRONG_PHASE,
|
||
'游戏未在进行中',
|
||
{
|
||
currentPhase: this.gameState.phase,
|
||
expectedPhase: 'PLAYING'
|
||
}
|
||
);
|
||
}
|
||
|
||
// 检查是否轮到该玩家
|
||
if (this.gameState.currentPlayerIndex !== this._getPlayerIndex(playerId)) {
|
||
return ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_INVALID_ACTION,
|
||
'不是该玩家的回合',
|
||
{
|
||
playerId: playerId,
|
||
currentPlayer: this.gameState.players[this.gameState.currentPlayerIndex].id
|
||
}
|
||
);
|
||
}
|
||
|
||
// 检查玩家是否持有该牌
|
||
var player = this._getPlayer(playerId);
|
||
if (!this._hasCard(player.handTiles, tileCode)) {
|
||
return ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_INVALID_CARD,
|
||
'玩家手中没有该牌',
|
||
{
|
||
playerId: playerId,
|
||
tileCode: tileCode,
|
||
handTiles: player.handTiles.map(function(t) { return t.code; })
|
||
}
|
||
);
|
||
}
|
||
|
||
// 验证通过
|
||
return null;
|
||
};
|
||
|
||
// 使用验证结果
|
||
OperationManager.prototype.performDiscard = function(playerId, tileCode) {
|
||
var validationError = this.validateDiscard(playerId, tileCode);
|
||
|
||
if (validationError) {
|
||
Logger.warn('OperationManager', '出牌验证失败', {
|
||
error: validationError.message,
|
||
code: validationError.code
|
||
});
|
||
return {
|
||
success: false,
|
||
error: validationError
|
||
};
|
||
}
|
||
|
||
// 执行出牌操作
|
||
// ...
|
||
|
||
return { success: true };
|
||
};
|
||
```
|
||
|
||
#### 场景3:安全执行包装
|
||
|
||
```javascript
|
||
// GameController.js
|
||
|
||
GameController.prototype.processPlayerAction = function(playerId, action) {
|
||
Logger.info('GameController', '处理玩家操作', {
|
||
playerId: playerId,
|
||
action: action.type
|
||
});
|
||
|
||
// 使用安全执行包装
|
||
var result = ErrorHandler.safeExecute(
|
||
function() {
|
||
// 可能抛出异常的代码
|
||
return this._executeAction(playerId, action);
|
||
},
|
||
this,
|
||
[]
|
||
);
|
||
|
||
if (!result.success) {
|
||
// 操作失败,记录错误
|
||
Logger.error('GameController', '操作执行失败', {
|
||
playerId: playerId,
|
||
action: action.type,
|
||
error: result.error.message
|
||
});
|
||
|
||
// 尝试恢复
|
||
var recovered = ErrorHandler.tryRecover(result.error, function() {
|
||
// 恢复到上一个有效状态
|
||
return this._rollbackToLastState();
|
||
}.bind(this));
|
||
|
||
if (recovered) {
|
||
Logger.info('GameController', '已成功从错误中恢复');
|
||
}
|
||
|
||
return {
|
||
success: false,
|
||
error: ErrorHandler.formatErrorMessage(result.error)
|
||
};
|
||
}
|
||
|
||
Logger.debug('GameController', '操作执行成功', {
|
||
playerId: playerId,
|
||
result: result.result
|
||
});
|
||
|
||
return {
|
||
success: true,
|
||
result: result.result
|
||
};
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠️ shared/utils - 共享工具类
|
||
|
||
### ArrayUtils.js - 数组操作工具
|
||
|
||
**功能**:提供数组操作的辅助方法
|
||
|
||
**常用方法**:
|
||
```javascript
|
||
// 数组去重
|
||
ArrayUtils.unique(array)
|
||
|
||
// 数组打乱(洗牌)
|
||
ArrayUtils.shuffle(array)
|
||
|
||
// 数组查找
|
||
ArrayUtils.findIndex(array, predicate)
|
||
|
||
// 数组分组
|
||
ArrayUtils.groupBy(array, keyFunc)
|
||
```
|
||
|
||
### CardSourceInfoHelper.js - 牌源信息辅助
|
||
|
||
**功能**:管理麻将牌的来源信息
|
||
|
||
**主要方法**:
|
||
```javascript
|
||
// 创建牌源信息
|
||
CardSourceInfoHelper.create(source, round, turn)
|
||
|
||
// 验证牌源信息
|
||
CardSourceInfoHelper.validate(sourceInfo)
|
||
```
|
||
|
||
### GameContextHelper.js - 游戏上下文辅助
|
||
|
||
**功能**:管理游戏上下文信息
|
||
|
||
**主要方法**:
|
||
```javascript
|
||
// 创建游戏上下文
|
||
GameContextHelper.create(roomcode, round, phase)
|
||
|
||
// 更新上下文
|
||
GameContextHelper.update(context, updates)
|
||
```
|
||
|
||
### GameStateHelper.js - 游戏状态辅助
|
||
|
||
**功能**:游戏状态的辅助操作
|
||
|
||
**主要方法**:
|
||
```javascript
|
||
// 验证游戏状态
|
||
GameStateHelper.validate(gameState)
|
||
|
||
// 克隆游戏状态
|
||
GameStateHelper.clone(gameState)
|
||
|
||
// 比较游戏状态
|
||
GameStateHelper.compare(state1, state2)
|
||
```
|
||
|
||
### MahjongCardUniqueId.js - 麻将牌唯一ID
|
||
|
||
**功能**:生成和管理麻将牌的唯一标识
|
||
|
||
**主要方法**:
|
||
```javascript
|
||
// 生成唯一ID(10-145)
|
||
MahjongCardUniqueId.generate(code, index)
|
||
|
||
// 从唯一ID获取牌码
|
||
MahjongCardUniqueId.getCode(uniqueId)
|
||
|
||
// 验证唯一ID
|
||
MahjongCardUniqueId.validate(uniqueId)
|
||
```
|
||
|
||
### RoomConfigUtils.js - 房间配置工具
|
||
|
||
**功能**:房间配置的解析和验证(详见 [06-规则配置系统.md](../core/06-规则配置系统.md))
|
||
|
||
---
|
||
|
||
## 💡 使用最佳实践
|
||
|
||
### 1. 日志级别选择
|
||
|
||
```javascript
|
||
// ✓ 推荐:根据环境设置日志级别
|
||
if (process.env.NODE_ENV === 'production') {
|
||
Logger.setLevel('WARN'); // 生产环境只记录警告和错误
|
||
} else {
|
||
Logger.setLevel('DEBUG'); // 开发环境记录调试信息
|
||
}
|
||
|
||
// ✓ 推荐:使用合适的日志级别
|
||
Logger.trace('Module', '详细跟踪信息'); // 非常详细,仅开发调试用
|
||
Logger.debug('Module', '调试信息'); // 开发时使用
|
||
Logger.info('Module', '正常运行信息'); // 关键流程节点
|
||
Logger.warn('Module', '警告信息'); // 可能的问题
|
||
Logger.error('Module', '错误信息'); // 功能异常
|
||
Logger.fatal('Module', '致命错误'); // 系统无法继续
|
||
|
||
// ✗ 不推荐:滥用日志级别
|
||
Logger.error('Module', '玩家进入房间'); // 这应该是INFO级别
|
||
Logger.info('Module', '系统崩溃'); // 这应该是FATAL级别
|
||
```
|
||
|
||
### 2. 日志标签规范
|
||
|
||
```javascript
|
||
// ✓ 推荐:使用清晰的标签
|
||
Logger.info('GameController', '游戏开始');
|
||
Logger.debug('MahjongService', '发牌完成');
|
||
Logger.warn('OperationManager', '操作超时');
|
||
|
||
// ✗ 不推荐:标签不清晰
|
||
Logger.info('GC', 'start'); // 太简短
|
||
Logger.info('游戏', '开始'); // 使用中文不便于过滤
|
||
```
|
||
|
||
### 3. 附加数据使用
|
||
|
||
```javascript
|
||
// ✓ 推荐:提供有用的上下文信息
|
||
Logger.error('RpcHandler', 'RPC调用失败', {
|
||
method: 'player_discard',
|
||
playerId: 'player001',
|
||
errorCode: 2001,
|
||
timestamp: Date.now()
|
||
});
|
||
|
||
// ✗ 不推荐:数据过多或无用
|
||
Logger.info('Module', '操作', {
|
||
// 包含整个gameState对象(太大)
|
||
gameState: this.gameState
|
||
});
|
||
```
|
||
|
||
### 4. 性能考虑
|
||
|
||
```javascript
|
||
// ✓ 推荐:仅在需要时记录日志
|
||
if (Logger.config.currentLevel <= Logger.LOG_LEVELS.DEBUG) {
|
||
var expensiveData = this._calculateExpensiveData();
|
||
Logger.debug('Module', '详细数据', expensiveData);
|
||
}
|
||
|
||
// ✗ 不推荐:总是计算数据
|
||
var expensiveData = this._calculateExpensiveData();
|
||
Logger.debug('Module', '详细数据', expensiveData); // DEBUG被禁用时也会计算
|
||
```
|
||
|
||
### 5. 错误处理策略
|
||
|
||
```javascript
|
||
// ✓ 推荐:创建标准化错误
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_INVALID_ACTION,
|
||
'具体的错误描述',
|
||
{ 有用的上下文信息 }
|
||
);
|
||
|
||
// ✓ 推荐:使用安全执行
|
||
var result = ErrorHandler.safeExecute(riskyFunction, context, args);
|
||
if (!result.success) {
|
||
// 处理错误
|
||
}
|
||
|
||
// ✗ 不推荐:直接抛出字符串
|
||
throw '出错了'; // 没有错误码,无法分类
|
||
|
||
// ✗ 不推荐:忽略错误
|
||
try {
|
||
riskyOperation();
|
||
} catch (error) {
|
||
// 什么都不做,错误被吞噬
|
||
}
|
||
```
|
||
|
||
### 6. 日志和错误配合使用
|
||
|
||
```javascript
|
||
// ✓ 推荐:记录错误日志
|
||
try {
|
||
performOperation();
|
||
} catch (error) {
|
||
var standardError = ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_INVALID_ACTION,
|
||
error.message,
|
||
{ operation: 'performOperation' }
|
||
);
|
||
|
||
Logger.error('Module', '操作失败', {
|
||
error: standardError.message,
|
||
code: standardError.code
|
||
});
|
||
|
||
throw standardError;
|
||
}
|
||
|
||
// ✗ 不推荐:只记录日志或只抛出错误
|
||
try {
|
||
performOperation();
|
||
} catch (error) {
|
||
Logger.error('Module', error.message); // 只记录,不抛出
|
||
// 或
|
||
throw error; // 只抛出,不记录
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 调试技巧
|
||
|
||
### 1. 启用详细日志
|
||
|
||
```javascript
|
||
// 临时启用TRACE级别查看所有日志
|
||
Logger.setLevel('TRACE');
|
||
|
||
// 执行需要调试的代码
|
||
someFunction();
|
||
|
||
// 恢复原来的级别
|
||
Logger.setLevel('INFO');
|
||
```
|
||
|
||
### 2. 使用日志分组
|
||
|
||
```javascript
|
||
// 使用分组整理相关日志
|
||
Logger.group('===== 玩家操作处理 =====');
|
||
Logger.info('Operation', '验证玩家');
|
||
Logger.debug('Operation', '检查游戏状态');
|
||
Logger.debug('Operation', '执行操作');
|
||
Logger.info('Operation', '操作完成');
|
||
Logger.groupEnd();
|
||
```
|
||
|
||
### 3. 性能分析
|
||
|
||
```javascript
|
||
// 使用计时功能分析性能
|
||
Logger.time('完整游戏流程');
|
||
|
||
Logger.time('初始化');
|
||
initialize();
|
||
Logger.timeEnd('初始化');
|
||
|
||
Logger.time('发牌');
|
||
dealTiles();
|
||
Logger.timeEnd('发牌');
|
||
|
||
Logger.time('游戏进行');
|
||
playGame();
|
||
Logger.timeEnd('游戏进行');
|
||
|
||
Logger.timeEnd('完整游戏流程');
|
||
```
|
||
|
||
### 4. 查看错误历史
|
||
|
||
```javascript
|
||
// 获取最近的错误
|
||
var errors = ErrorHandler.getStatistics().recent;
|
||
Logger.table(errors);
|
||
|
||
// 分析错误分布
|
||
var stats = ErrorHandler.getStatistics();
|
||
Logger.info('ErrorStats', '错误统计', {
|
||
total: stats.total,
|
||
byLevel: stats.byLevel,
|
||
topErrors: Object.keys(stats.byCode)
|
||
.sort(function(a, b) {
|
||
return stats.byCode[b] - stats.byCode[a];
|
||
})
|
||
.slice(0, 5)
|
||
});
|
||
```
|
||
|
||
### 5. 日志过滤
|
||
|
||
```javascript
|
||
// 只查看特定级别的日志
|
||
var errorLogs = Logger.getHistory(null, Logger.LOG_LEVELS.ERROR);
|
||
var warnLogs = Logger.getHistory(null, Logger.LOG_LEVELS.WARN);
|
||
|
||
// 只查看最近的日志
|
||
var recent = Logger.getHistory(50); // 最近50条
|
||
|
||
// 自定义过滤
|
||
var gameLogs = Logger.getHistory().filter(function(log) {
|
||
return log.tag.indexOf('Game') !== -1;
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 完整使用示例
|
||
|
||
### 示例1:模块初始化
|
||
|
||
```javascript
|
||
// 模块入口文件
|
||
|
||
(function() {
|
||
'use strict';
|
||
|
||
// 配置Logger
|
||
Logger.configure({
|
||
currentLevel: Logger.LOG_LEVELS.DEBUG,
|
||
enableTimestamp: true,
|
||
enableColors: true,
|
||
moduleName: 'JinXianMahjong'
|
||
});
|
||
|
||
Logger.info('System', '======= 进贤麻将系统启动 =======');
|
||
Logger.info('System', '版本:', '1.0.0');
|
||
Logger.info('System', '环境:', process.env.NODE_ENV || 'development');
|
||
|
||
// 初始化系统
|
||
try {
|
||
Logger.group('系统初始化');
|
||
|
||
Logger.time('加载配置');
|
||
var config = loadConfiguration();
|
||
Logger.timeEnd('加载配置');
|
||
Logger.debug('System', '配置加载完成', config);
|
||
|
||
Logger.time('初始化数据库');
|
||
initializeDatabase();
|
||
Logger.timeEnd('初始化数据库');
|
||
Logger.info('System', '数据库初始化完成');
|
||
|
||
Logger.time('注册游戏模块');
|
||
registerGameModule();
|
||
Logger.timeEnd('注册游戏模块');
|
||
Logger.info('System', '游戏模块注册完成');
|
||
|
||
Logger.groupEnd();
|
||
Logger.info('System', '======= 系统启动完成 =======');
|
||
|
||
} catch (error) {
|
||
var systemError = ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.SYSTEM_INITIALIZATION_FAILED,
|
||
'系统初始化失败: ' + error.message,
|
||
{ error: error.stack },
|
||
ErrorHandler.ERROR_LEVELS.FATAL
|
||
);
|
||
|
||
Logger.fatal('System', '系统启动失败', {
|
||
error: systemError.message,
|
||
code: systemError.code
|
||
});
|
||
|
||
process.exit(1);
|
||
}
|
||
})();
|
||
```
|
||
|
||
### 示例2:完整的操作流程
|
||
|
||
```javascript
|
||
// 玩家出牌操作的完整流程
|
||
|
||
function handlePlayerDiscard(playerId, tileCode) {
|
||
Logger.info('DiscardHandler', '======= 处理玩家出牌 =======', {
|
||
playerId: playerId,
|
||
tileCode: tileCode
|
||
});
|
||
|
||
try {
|
||
Logger.group('出牌验证');
|
||
|
||
// 1. 参数验证
|
||
Logger.debug('Validation', '验证参数');
|
||
if (!playerId || !tileCode) {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.INTERFACE_INVALID_PARAMS,
|
||
'出牌参数无效',
|
||
{ playerId: playerId, tileCode: tileCode }
|
||
);
|
||
}
|
||
|
||
// 2. 玩家验证
|
||
Logger.debug('Validation', '验证玩家');
|
||
var player = getPlayer(playerId);
|
||
if (!player) {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.INTERFACE_PLAYER_NOT_FOUND,
|
||
'玩家不存在',
|
||
{ playerId: playerId }
|
||
);
|
||
}
|
||
|
||
// 3. 游戏状态验证
|
||
Logger.debug('Validation', '验证游戏状态');
|
||
var gameState = getGameState();
|
||
if (gameState.phase !== 'PLAYING') {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_WRONG_PHASE,
|
||
'游戏未在进行中',
|
||
{ currentPhase: gameState.phase }
|
||
);
|
||
}
|
||
|
||
// 4. 回合验证
|
||
Logger.debug('Validation', '验证玩家回合');
|
||
if (!isPlayerTurn(playerId)) {
|
||
throw ErrorHandler.createError(
|
||
ErrorHandler.ERROR_CODES.GAME_INVALID_ACTION,
|
||
'不是该玩家的回合',
|
||
{ playerId: playerId, currentPlayer: getCurrentPlayer() }
|
||
);
|
||
}
|
||
|
||
Logger.groupEnd();
|
||
Logger.info('Validation', '验证通过');
|
||
|
||
// 5. 执行出牌
|
||
Logger.group('执行出牌');
|
||
Logger.time('出牌操作');
|
||
|
||
var result = ErrorHandler.safeExecute(
|
||
function() {
|
||
return performDiscard(player, tileCode);
|
||
},
|
||
this,
|
||
[]
|
||
);
|
||
|
||
Logger.timeEnd('出牌操作');
|
||
|
||
if (!result.success) {
|
||
throw result.error;
|
||
}
|
||
|
||
Logger.info('Discard', '出牌成功', {
|
||
playerId: playerId,
|
||
tileCode: tileCode,
|
||
discardedTile: result.result
|
||
});
|
||
|
||
Logger.groupEnd();
|
||
|
||
// 6. 检查其他玩家的响应
|
||
Logger.group('检查玩家响应');
|
||
var responses = checkPlayerResponses(tileCode);
|
||
Logger.debug('Response', '玩家响应', responses);
|
||
Logger.groupEnd();
|
||
|
||
// 7. 广播消息
|
||
Logger.debug('Broadcast', '广播出牌消息');
|
||
broadcastDiscard(playerId, tileCode, responses);
|
||
|
||
Logger.info('DiscardHandler', '======= 出牌处理完成 =======');
|
||
|
||
return {
|
||
success: true,
|
||
result: {
|
||
playerId: playerId,
|
||
tile: tileCode,
|
||
responses: responses
|
||
}
|
||
};
|
||
|
||
} catch (error) {
|
||
Logger.error('DiscardHandler', '出牌处理失败', {
|
||
error: error.message,
|
||
code: error.code,
|
||
playerId: playerId,
|
||
tileCode: tileCode
|
||
});
|
||
|
||
// 记录错误统计
|
||
var stats = ErrorHandler.getStatistics();
|
||
Logger.warn('DiscardHandler', '当前错误统计', {
|
||
total: stats.total,
|
||
recent: stats.recent.length
|
||
});
|
||
|
||
return {
|
||
success: false,
|
||
error: ErrorHandler.formatErrorMessage(error)
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 相关文档链接
|
||
|
||
- **上一篇**:[06-规则配置系统.md](../core/06-规则配置系统.md) - 规则配置解析
|
||
- **下一篇**:[08-游戏流程概述.md](../architecture/08-游戏流程概述.md) - 完整游戏流程
|
||
- **参考**:
|
||
- [03-RPC处理机制.md](../framework/03-RPC处理机制.md) - RPC错误处理
|
||
- [04-游戏核心服务.md](../core/04-游戏核心服务.md) - 服务层日志使用
|
||
|
||
---
|
||
|
||
## 📝 附录
|
||
|
||
### A. Logger配置选项完整列表
|
||
|
||
```javascript
|
||
{
|
||
currentLevel: 0-5, // 当前日志级别
|
||
enableConsole: true/false, // 启用控制台输出
|
||
enableColors: true/false, // 启用颜色
|
||
enableTimestamp: true/false, // 启用时间戳
|
||
enableModuleName: true/false, // 启用模块名
|
||
enableStackTrace: true/false, // 启用堆栈跟踪
|
||
timestampFormat: 'ISO'/'LOCAL'/'TIMESTAMP', // 时间戳格式
|
||
moduleName: 'string', // 模块名
|
||
maxLogHistory: number, // 最大历史记录数
|
||
flushInterval: number // 刷新间隔(毫秒)
|
||
}
|
||
```
|
||
|
||
### B. 错误代码快速查询
|
||
|
||
| 范围 | 类别 | 说明 |
|
||
|------|------|------|
|
||
| 1000-1999 | 框架接口错误 | Export/Import接口相关 |
|
||
| 2000-2999 | 游戏逻辑错误 | 游戏规则和操作相关 |
|
||
| 3000-3999 | 数据验证错误 | 参数和数据格式验证 |
|
||
| 4000-4999 | 业务逻辑错误 | 业务规则和状态相关 |
|
||
| 5000-5999 | 网络通信错误 | 网络连接和通信相关 |
|
||
| 9000-9999 | 系统错误 | 系统级别的严重错误 |
|
||
|
||
### C. 常用日志模式
|
||
|
||
```javascript
|
||
// 1. 方法入口/出口模式
|
||
function someMethod(param) {
|
||
Logger.debug('Module', 'someMethod 入口', { param: param });
|
||
try {
|
||
// 方法逻辑
|
||
var result = doSomething(param);
|
||
Logger.debug('Module', 'someMethod 出口', { result: result });
|
||
return result;
|
||
} catch (error) {
|
||
Logger.error('Module', 'someMethod 异常', { error: error.message });
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// 2. 状态变更模式
|
||
function changeState(newState) {
|
||
Logger.info('StateManager', '状态变更', {
|
||
from: this.currentState,
|
||
to: newState
|
||
});
|
||
this.currentState = newState;
|
||
}
|
||
|
||
// 3. 性能监控模式
|
||
function performanceMonitor(operation) {
|
||
Logger.time(operation.name);
|
||
var result = operation.execute();
|
||
Logger.timeEnd(operation.name);
|
||
return result;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
**文档版本**:v1.0
|
||
**最后更新**:2025年10月15日
|
||
**维护者**:进贤麻将开发团队
|