“上线完毕!!!”后端群里传来“捷报”。But半小时后...
移动端群里机器人发来告警:

日常bug崩溃率稳定在0.06%左右,崩溃率突然激增了8倍!!!起床查bug吧[流泪]。
第一时间打开U-APM,查看近一小时奔溃统计,看到排在第一的bug:

原来是个空指针异常,在看下崩溃前的用户行为统计:

通过日志很快的定位了崩溃页面,postman看一下接口返回数据,原来有一个String类型返回了null,同时客户端正好也刚改用Gson没有做好兼容导致崩溃(虽然bean有设默认值,但是Gson解析是直接通过反射完成,跨过了kotlin的默认值)。于是通知后端紧急修复先确保线上不报错。随后客户端通过自定义Gson TypeAdapter方式做了兼容。凭借U-APM监控告警+Bug追踪,从收到告警到fix bug用时十分钟,阻止了影响进一步扩大。

说到U-APM的使用,还经历了下面几个阶段:

初级阶段

Case1:堆栈日志无法定位到个人代码,通过分析用户行为数据特点定位Bug

之前我们开发中遇到一个bug,堆栈信息如下:

整个报错信息没有一句自己的代码,将错误日志google一下,大多多说Bundle传输时装的数据体积太大,于是无奈之下review了项目中所有Bundle传输相关代码,无果!后来发现友盟U-APM可以看崩溃前的用户行为日志,看了一下发现都是WebView相关页面报的错,由于项目中很多和h5交互的,还是无法定位哪个页面。
但是通过进一步分析多条用户行为日志发现两个规律:

1 用户崩溃前访问页面和上一个页面有好几个小时的时间差。

2 这个时间差越长,崩溃日志的 “data parcel size xxx bytes”数值xxx就越大。
因此可以得出两个结论:
1 用户是在上一次使用后切后台,几个小时候切回前台使用时崩溃。(用户不可能停在一个页面好几个小时)
2 在后台期间应该有个累积操作,使parcel size持续变大,这个操作可能是轮询。
带着这两个结论,我们检查了h5代码,发现确实有轮询请求通过h5调原生的方式使用okhttp请求网络,App在后台的请求结果可能暂存parcel,App返回前台时parcel size超出了bundle承载上限导致崩溃。后来修改为切后台后停止轮询,新版本该bug消失[成功]。

Case2:通过云真机定位非主流机型 Bug
我们例行查看umeng上收集的bug时,发现一个特殊的bug,只出现在低版本的vivo手机上:

我们的测试机好多都是近两年采购的,去哪找这种手机测试啊[破涕为泪]。突然发现友盟 U-APM有云真机功能,搜了一下,还真有6.0系统的vivo手机,传包安装上去测了一下,如期崩溃了

google后发现网上也有朋友遇到类似问题:问题链接。后来联系到vivo技术支持,得知是vivo系统的bug,按vivo给出的解决方案修改后重新云真机测试通过,上线!

进阶使用

1增加用户自定义字段
通过自定义字段记录崩溃前用户id,用户更具体的行为,用户网络请求等信息,用这些信息来帮助定位问题。下面是我们一bug的自定义字段截图:

2 接入监控提醒
我们使用U-APM的监控功能创建了监控告警规则,并使用WebHook将告警信息及时通知到我们的企业微信群。(如文章开篇那种通知)

3 添加自定义异常
通过自定义异常上报已经catch的异常以及影响使用的非崩溃异常。虽然这类异常直接当成一个事件统计也可以上报给友盟,但是以异常的形式上报可以触发告警规则。(告警可以监控自定义异常)。如下图是我们监控到的一个非崩溃,但是对我们来说比较严重的异常:

未来篇

U-APM + Arms + EMAS热更新

由于我们后端也用了阿里的arms监控,所以我们后期定位bug可以前后端监控联动,比如通过前端错误日志的时间和用户id(可以手动查看也可以通过U-APM OpenAPI获取)结合后端arms日志一起分析,像开篇这种bug就可以以更短时间发现后端返回数据中的错误点,进而更快得定位bug。
同时接入阿里云EMAS的移动热修复功能,做到不发布直接更新。

小Tip:

因为友盟的页面自动统计hook了iOS 的生命周期方法,如果开发者用Aspects进行一些AOP操作需要hook生命周期方法时,hook代码需要写在友盟初始化之后,否则会出现多次hook冲突报以下异常:

只要保证友盟先初始化就ok。
最后,感谢 友盟+ U-APM 提供这样实用且好用平台助我们产出稳定高性能的应用。

作者:郭栋浩


性能优化实践者
11 声望220 粉丝