原因
这几天,公司开发的小程序有部分用户用户打开咨询列表页显示空白,我们查后台日志没有错误。最让人头疼的是,这种前端显示不正确,只是在某些机型上才出现,我们的测试人员无法复现该问题。无法复现,又没有错误日志记录,这种问题咋解决?
方案1
思前想后,我们需要将小程序端所有的错误日志记录下来,并上传给后台。因为小程序的特性,除了App.js,所有其他的逻辑都在Page函数中,我们只需要处理Page函数中所有的方法,结合之前的一篇《微信小程序重写Page函数,实现全局日志记录》,我们可以在那基础上继续改写Page函数,使用try catch捕获所有函数的异常,然后将捕获的异常信息上传到服务端。
微信小程序最近推出了小程序的实时日志,结合小程序的实时日志后,我们不需要写相关的后端代码,可将异常信息上传到小程序的平台。(点击链接可查看实时日志详情和使用方式,这里不在多描述)
function init(_data) { data = _data // 重写page函数,增加阿里云监控 let oldPage = Page Page = function(obj) { // 对Page的传参obj对象的所有函数进行异常捕捉 for (let key in obj) { let oldFunction = obj[key] if (typeof oldFunction === 'function') { obj[key] = function() { try { // 日志埋点 if (['onShow', 'onHide'].includes(key)) { log.info('执行了' + this.__route__ + '的' + key + '方法') key === 'onShow' ? enterPageLog() : leavePageLog() } return oldFunction.call(this, ...arguments) } catch (e) { // 上传信息到小程序实时日志 var log = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : null log || log.error.call(log, '发生了错误!页面:' + this.__route__ + ',方法:' + key + ',错误信息:' + e.message) throw e } } } } return oldPage(Monitor.hookPage(obj)) }}这样就通过实时日志功能上传了错误日志到微信小程序的管理后台,通过https://mp.weixin.qq.com登录小程序管理端,就能看到实时日志,通过openid筛选就能查看到对应用户的错误日志,从而排查问题了。

方案2
但微信小程序的错误日志感觉不全,微信那边应该是做了流控或是采样,有些错误没有抓到,造成排查问题的困难。
还是自己动手吧,将错误信息上传到后端。代码如下,只修改了上面上传日志的那一部分
function init(_data) { data = _data // 重写page函数,增加阿里云监控 let oldPage = Page Page = function(obj) { // 对Page的传参obj对象的所有函数进行异常捕捉 for (let key in obj) { let oldFunction = obj[key] if (typeof oldFunction === 'function') { obj[key] = function() { try { // 日志埋点 if (['onShow', 'onHide'].includes(key)) { log.info('执行了' + this.__route__ + '的' + key + '方法') key === 'onShow' ? enterPageLog() : leavePageLog() } return oldFunction.call(this, ...arguments) } catch (e) { const errInfo = '发生了错误!页面:' + this.__route__ + ',方法:' + key + ',错误信息:' + e.message console.error(errInfo) // 上传信息到服务端 wx.request({ url: host + '/addWebLog', method: 'POST', data: { errInfo: errInfo } }) throw e } } } } return oldPage(Monitor.hookPage(obj)) }}上传到服务器的错误信息包含当前用户、报错页面、报错方法和错误信息,这样我们在服务端就能查看到前端的异常了。
后端处理
新建一个controller来接收这个请求,用于接收前端上传的数据。
@RestControllerpublic class LogController { private Logger logger = LoggerFactory.getLogger(LogController.class); private LinkedBlockingQueueWebLog queue; private Integer Queue_Capacity = 1000; //队列的容量 @Autowired private JdbcTemplate jdbcTemplate; @PostConstruct public void init() { queue = new LinkedBlockingQueue(Queue_Capacity); Thread thread = new Thread(() - { while (true) { try { // 从队列末尾取,取不到则阻塞 WebLog webLog = queue.take(); logger.info("前端出错:" + JSONObject.toJSONString(webLog)); // 数据库操作 jdbcTemplate.update("insert into web_log(err_info) values(?)", webLog.getErrInfo()); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); } @PostMapping("/addWebLog") public MonoVoid addWebLog(WebLog webLog) { // 到达capacity则抛出异常 try { queue.add(webLog); } catch (IllegalStateException e) { System.out.println("队列达到上限:" + queue.size()); } return Mono.empty(); } public class WebLog { private String errInfo; public String getErrInfo() { return errInfo; } public void setErrInfo(String errInfo) { this.errInfo = errInfo; } }}为了防止某个功能有bug、大批量出错造成服务器压力,这里添加了一个队列来异步处理请求。Controller收到请求只是将请求丢到队列里,另外一个线程中队列在一个一个取出请求进行处理。队列长度为1000,超过1000的请求直接丢弃。
结语
微信虽然提供了小程序实时日志
其实微信提供了一种错误查询,在微信公众平台小程序可以查看到,但是和小程序实时日志一样有点不好用,我感觉这俩都是对错误进行采样,不是抓取全部错误。例如:开头我描述的那个错误就没找到。
还是自己动手,重写Page函数,catch所有异常,将错误上传给后台比较好排查问题。
小程序













