我们在使用cocosCreator开发游戏,如果游戏上线,出现了bug我们一般是不知道的,除了玩家反馈。而且算有玩家反馈,也不知道具体是哪里出现了问题。我这里是做了一个全局的错误监听,然后将错误日志上报到服务器,然后通过上报的错误日志来定位问题。甚至可以发现很多玩家没有反馈到的bug。
创建全局错误监听
这里注意,不同的错误类型监听方法不一样,而且只在web
端生效,如果是原生端,这里的监听是不会上报的。
1 | window.onerror = (message, source, lineno, colno, error) => { |
这里需要注意几点:
- 上报的接口要改成你自己的,我这里是随便写的一个
- 在捕获全局错误
window.onerror
时,一旦触发可能就是无限触发,会导致游戏卡死的那种,只有杀掉进程才能恢复。所以我做了一个判断,如果行号和列号和上一次相同,并且错误信息相同,则不再上报,减少服务器的压力。
查看问题及解决方法
查看上面的报错日志,这里以下面日志为例:
1 | {"message":"Cannot read properties of null (reading 'length')","stack":"TypeError: Cannot read properties of null (reading 'length')\n |
上面的日志说明在调用 getChildByName
返回了 null
,然后代码里尝试读取它的 length
属性,导致空指针异常。
解决方法
解决方法有很多,比如直接全局搜索wathcTheGame
方法,看具体时哪里出错了,但是如果这个方法用的地方比较多,可能也判断不出具体的问题。
再或者打包时关闭代码混淆,本地测试可以用,但是上传到正式服不建议这么做。
推荐方法,利用SourceMap
在打包的时候,勾选择SourceMap
,这样打包的时候给每个.js
文件生成一个和源码映射的.map
文件。如果是线上环境,不建议上传相关的.map
文件。后面我们在排查错误的时候,可以通过这个.map
文件来找我们出问题的源代码。
使用方法:
- 打包时勾选
SourceMap
- 安装
source-map
使用下面命令行进行全局安装:1
npm install source-map
- 创建一个 JS 脚本,比如叫 lookupSourceMap.js,内容如下:运行示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20const fs = require('fs');
const sourceMap = require('source-map');
async function lookup(mapFile, line, column) {
const rawSourceMap = JSON.parse(fs.readFileSync(mapFile, 'utf-8'));
const consumer = await new sourceMap.SourceMapConsumer(rawSourceMap);
const pos = consumer.originalPositionFor({ line: line, column: column });
console.log('原始源码位置:', pos);
consumer.destroy();
}
const [,, mapFile, line, column] = process.argv;
if (!mapFile || !line || !column) {
console.error('用法: node lookupSourceMap.js path/to/file.js.map 行 列');
process.exit(1);
}
lookup(mapFile, Number(line), Number(column));输出示例:1
node lookupSourceMap.js ./cc.js.map 1 383931 // 后面分别是行号和列号
如下图所示:1
2
3
4
5
6原始源码位置: {
source: 'src/game/watchTheGame.ts',
line: 120,
column: 15,
name: 'watchTheGame'
}