阅读 1802

T 沙龙移动实践日总结 —— 蜂鸟团队移动端异常监控体系建设

下面是 T 沙龙小编对分享的一些总结:

PPT 和 视频

视频地址
PPT地址

蜂鸟团队移动端异常监控体系建设

第二个主讲人是饿了么蜂鸟团队 Android 端负责人 - 潘万坤。
从事安卓开发 6 年,先后在格瓦拉、饿了么等公司从事安卓开发工作。目前担任饿了么物流移动团队安卓负责人,主要关注移动端代码架构、性能优化等领域,负责保障 App 在线上的高稳定运行。他带来的是饿了么正在投入使用的移动端异常监控体系。

问题背景

在公司以往使用的常规 APM 系统及异常上报的数据中,存在以下三种问题:

  • Crash、ANR 等异常情况过于单一,很难进行进一步的分类;
  • 线上环境复杂,多数的 Case 均为测试和开发在日常的业务流程中无法覆盖的情况,复现难度过高,也具有一定的实效性;
  • 除了对异常情况处理的被动防御,提高发版质量的要求可以更加主动的解决问题;

于是针对这些问题,饿了么蜂鸟团队做了一套移动端异常监控体系来处理所有的问题,下面就是整个体系的结构图:

)

TimeBomb (自定义异常监控系统)

我们将其起名为TimeBomb,代表着一段时间内连续出现 N 次的异常。这种问题在蜂鸟产品的中暴露的场景有很多,例如登陆异常迭代异常定位异常大图片申请卡顿等。

我们通过实时监控数据,可以找到集中的上报问题。这里横轴反映的是时间区段,纵轴代表上报数目,而且还有很多的 filter 选项来控制是否展示数据曲线,可帮助我们只关注某几个上报日志的情况。

另外,对于日常关注打点,我们可以通过后台配置来控制前端上报曲线的展示情况。其他的,可以根据某一字段进行查询,也可对某一个打点进行更深入的探究。

T 沙龙小编注:与 Kibana 系统极为相似;优势在于可以在配置中增加我们所需要的数据,对 PM 和数据分析人员较为友好,具有数据的实时关注性。

Dogger日志系统

Dogger 日志系统 其实和日常的日志系统关注点一样,主要有四大关注要素:生命周期-Life点击事件-Click网络请求-Http自定义-Custom。并且在这基础上,Dogger还有一些更加优势的特点:

  • 通过 mmap 进行写文件,让打点日志记录更加高效;
  • 云控平台实现远端配置,可做到实时配置,及时上传;
  • 压缩比高,更加节省用户端的流量;
  • 对于敏感信息,采用强大的加密算法,保障安全性;
  • 可生成自动化脚本,功能强大;

Talk is cheap,所以蜂鸟团队开源了 Dogger 日志系统,详见我们的 GitHub

(项目即将从 Trojan 更名成 Dogger)

DoggerService

针对于客户端的强大 Dogger 日志系统,服务端也对应的推出了一套 DoggerService 来展示 Dogger 系统收集到的日志信息,做到很好的归类。DoggerService 目前正在建设阶段,以下列出寄予 DoggerService 的几个小目标:

  • 可以优雅的展示日志内容;
  • 对埋点的事件频率做直观的展示;
  • 对特定的业务模块有一定的数据分析能力;

目前,我们的 DoggerService 已经完成了大部分内容,下面是一些已经竣工的效果图:

DoggerMonitor

无论是 Dogger日志系统 还是 DoggerService 的日志记录归纳和数据汇总系统,可以说都是在问题暴露了之后的排查手段。当然作为更加主动的开发者,保证开发和打包质量其实才是我们解决问题更加积极的方法。DoggerMonitor开发监控就是为了满足这一需求从而诞生出的一个工具。

DoggerMonitor 与业务开发人员的开发体验息息相关。将其集成在 App 中后,我们可通过悬浮窗来实时查看 FPS、CPU、内存占用这些经常关注的指标。点击浮窗进入后也有具体的指标监控和历史记录曲线。在调试过程中的堆栈情况也可在客户端中实时记录,这一功能对于 QA 测试人员在发现问题上报给研发做 Debug 时具有很好的定位问题的能力。

根据组内开发同学和 QA 同学的需求,我们对 DoggerMonitor 作出了一套适用于这些需求的架构:

总的来看,集成 DoggerMonitor 十分容易,因为是通过 AOP 的无侵入方式来将功能集成。我们为每一种数据采集模块增加了 Dogger-Support 插件来提供多种数据。

最后所有的数据都放置到了前端数据库里。

方法耗时 - Mirror

使用 Mirror 库在对目的方法计算耗时,并记录 Class 信息和参数信息。

void method(){
    long startTime = System.currentTimeMillis();
    ...
    ...
    long endTime = System.currentTimeMillis();
    MirrorUtils.mirror(endTime - startTime, className + methodName + params);
}
复制代码

卡顿 - BlockCanary

卡顿检测团队使用了 BlockCanary 这套开源的方案。BlockCanary 对主线程操作进行了完全透明的监控,并能输出有效的信息,帮助开发分析、定位到问题所在,迅速优化应用。这套方案有以下特点:

  • 非侵入式,简单的两行就打开监控,不需要到处打点,破坏代码优雅性。
  • 精准,输出的信息可以帮助定位到问题所在(精确到行),不需要像Logcat一样,慢慢去找。

Android 中有一个16毫秒原则,即在 60Hz 的刷新频率下,在 16毫秒之内完成绘制则会有更佳的用户体验而不感觉卡顿。

Choreographer.getInstance()
    .postFrameCallback(new Choreographer.FrameCallback() {
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public void doFrame(long l) {
            BlockCanaryManager.getInstance().stop(runnable);
            BlockCanaryManager.getInstance().start(runnable , TIME_BLOCK);
        }
    });
复制代码

流量统计 - TNet

TNet 一期是对于 HTTP 接口的监控。所以最初我们只对 HTTP 请求做了一个 hook,从而记录了 request 和 response 的长度。

public class TNetInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
     
        recordHttp(request);
        recordHttp(response);
         
        return response;
    }
}
复制代码

对于三方的网络请求,通过 AOP 的方案,okhttp3.OkHttpClient 中将我们的 interceptors 方法 hook 进去,这样就能统计到所有的 HTTP 请求情况。

@TargetClass("okhttp3.OkHttpClient")
@NameRegex("okhttp3/RealCall")
@Proxy("networkInterceptors")
public List<Interceptor> networkInterceptors() {
    List<Interceptor> interceptors = (List<Interceptor>) Origin.call();
    List<Interceptor> newList = new ArrayList<>(interceptors.size() + 1);
    newList.addAll(interceptors);
    
    newList.add(new TNetInterceptor());
    
    return newList;
}
复制代码

在蜂鸟的产品 APP 中,除了 HTTP 请求之外,还有其他的情况。所以二期打算做一个统计完整流量的方案。querySummary 方法可以根据不同的网络类型和开始结束时间具体查询某一个请求的流量情况。但是这需要用户的权限。

BUILD_VERSION >= 23

NetworkStatsManager.querySummary(ConnectivityManager.TYPE_MOBILE,
        uid,
        startTime,
        endTime);
        
BUILD_VERSION < 23
TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid);
复制代码

大图片检测 - ImageWatcher

在打包过程中,ImageWatcher 会检测工程中的所有图片。通过 computeSize 换算公式,可以根据不同的文件目录去匹配各种的分辨率在将图片加载到手机中 Bitmap 的大小。这样,在打包时如果发现图片 Bitmap 大小超出阈值,就可以抛出一个错误,来提醒开发者图片有问题。

public int computeSize(int targetDensity) {
    if (density == Image.DEFAULT) {
        return width * height * 4;
    } else {
        return (int) ((width * targetDensity / density + 0.5f)
                * (height * targetDensity / density + 0.5f)
                * 4);
    }
}
复制代码

另外通过 Hook BitmapFactory 的产生方法,打印出 Bitmap 的信息,获取到其使用大小,同样超过阈值抛出异常。

总结

通过对蜂鸟团队移动端异常监控体系的建设,主要解决了在业务人员在开发过程中的以下三个痛点:

  1. 线上异常的及时上报;
  2. 提高问题追查的效率;
  3. 保障开发版本的质量;

全套系统团队均有开源的计划,而不只是 Dogger。整个监控系统仍旧在建设中,也希望各位开发者多多提 issue 和 pull request,一起打造更加完善的监控平台。另外,对于 DoggerService 的展望,可以与 QA 人员协助完成自动化测试流程,从而达到真正的 BDD 行为驱动开发的模式;另外 DoggerService 还需要更加强大的服务端后台支持,这也是蜂鸟团队在未来将要完善的组件。

关注下面的标签,发现更多相似文章
评论