本文基于MacOS,介绍如何基于ACRA(Application Crash Reporting on Android)构建数据采集系统。 阅读本文之前,读者需要了解:在MacOS下通过brew安装软件包。
1. ACRA简介
ACRA(Application Crash Reporting on Android),Android应用程序崩溃上报系统。在客户端集成ACRA的SDK,便可将应用程序的崩溃错误上报到服务端。ACRA内部实现了崩溃上报的策略,客户端采用Annotation的方式进行代码集成,对已有的业务代码影响非常小。
2. 服务端Acralyzer
实际上,ACRA并不限制服务端采用什么实现,现有第三方服务端有很多,譬如:Cloudant、IrisCouch、Couchhappy、Tracepot等; 如果不想使用第三方的,也可以自建服务端,Acralyzer是ACRA的服务端官方实现案例,除此之外,还有很多其他可用的服务端框架,PHP、Ruby、Go语言实现的都有,譬如:BrokenOpenApp、Acracadabra、acra-go。
本文采用Acralyzer在本地自建服务端,如要选择其他服务端,请参考https://github.com/ACRA/acra/wiki/Backends
2.1 安装CouchDB
$ brew install couchdb
...
To test CouchDB run:
curl http://127.0.0.1:5984/
The reply should look like:
{"couchdb":"Welcome","uuid":"....","version":"1.7.1","vendor":{"version":"1.7.1-1","name":"Homebrew"}}
To have launchd start couchdb now and restart at login:
brew services start couchdb
Or, if you don't want/need a background service you can just run:
couchdb
安装完成后会有提示:
- 使用
brew services start couchdb
命令可以将CouchDB作为常驻服务自动启动 - 使用
couchdb
命令可以启动CouchDB一次 - 正常运行CouchDB后,可以使用
curl http://127.0.0.1:5984/
命令进行测试 - CouchDB的配置文件在/usr/local/etc/couchdb目录下
2.2 安装Acralyzer
CouchDB不仅是一个数据库,还是Web服务器,在浏览器中打开http://127.0.0.1:5984/_utils/,便可看到CouchDB的管理界面:
默认情况下,有名为_replicator和_users的两个数据库。接下来,需要根据业务逻辑构建新的数据库和Web应用。Acralyzer包含两个组件:
- acra-storage:用于存储上报数据 https://github.com/ACRA/acra-storage.git
- acralyzer:用于展示数据报表 http://github.com/ACRA/acralyzer.git
根据Acralyzer的官方介绍,CouchDB 1.2.0及以上的版本支持快速安装这两个组件,使用Replicator功能即可:
在CouchDB的管理页,点击Replicator,便可以复制已有的数据库。
-
对于acra-storage,按照如下参数填写表单后,再点击Replicate按钮,稍作等待,便可将远程的数据库复制到本地,本地的数据库名字建议以acra-为前缀:
from Remote Database: http://get.acralyzer.com/distrib-acra-storage to Local Database: acra-<appname>
-
对于acralyzer,表单中填入以下参数,按照相同的操作即可:
from Remote Database: http://get.acralyzer.com/distrib-acralyzer to Local Database: acralyzer
笔者使用CouchDB 1.7.0版本,Replicator无法正常工作,需要使用CouchDB 2.1.1版本才行,而且Replicate操作执行的时间比较长(笔者的网络环境下需要等待约50分钟),直到acralyzer这个数据库构建成功,才能打开http://127.0.0.1:5984/acralyzer/_design/acralyzer/index.html,否则打开此网页会一直出现如下错误:
{"error":"not_found","reason":"missing"}
这是因为acralyzer/_design/acralyzer/index.html这个页面还没有被复制到本地的数据库中。官网也有手工安装acra-storage和acralyzer两个组件的教程,笔者在MacOS下尝试手工安装,却失败了。
正确安装Acralyzer后,打开http://127.0.0.1:5984/_utils/的Database界面,会看到新增的两个数据库:acra-<appname>
和acralyzer
,这两个数据库所包含的文件数量(# of Docs)应该都大于1:
2.3 Acralyzer配置
CouchDB和Acralyzer安装完毕后,打开http://127.0.0.1:5984/acralyzer/_design/acralyzer/index.html,便可以进入Acralyzer的主界面了,要采集客户端的上报数据,首先需要创建一个用户:
在导航栏的Admin选项卡中,选择Users,输入User name和Password,点击Create user,便可创建用户:
这时,会生成一段代码,这段代码需要集成到客户端,后文我们再来解释其含义。此处,只需要理解,Acralyzer的一个User就是一个客户端的上报标识。
使用127.0.0.1:5984这样的地址,客户端是无法访问的,因此正式环境下,需要进行域名和服务器的部署。在本地的测试环境下,可以使用隧道技术,将127.0.0.1:5984映射成一个外网可以访问的域名。 笔者使用gotunnel,下载对应平台的版gotunnel版本后,执行以下命令:
$ ./ngrok -config "ngrok.conf" -subdomain duanqz -proto http 5984
Tunnel Status online
Version 1.7/1.7
Forwarding http://duanqz.gotunnel.net -> 127.0.0.1:5984
2.4 常见错误
2.4.1 CouchDB没有启动
$ curl http://127.0.0.1:5984/
curl: (7) Failed to connect to 127.0.0.1 port 5984: Connection refused
在控制台执行couchdb
命令即可启动。
2.4.2 Replicator不能正常工作
在使用CouchDB 1.7.0版本的Replicator复制远程数据库时一直失败,可能会出现如下错误:
[error] [<0.16696.0>] ** Generic server <0.16696.0> terminating
** Last message in was {'EXIT',<0.16695.0>,killed}
** When Server state == {state,"http://get.acralyzer.com/distrib-acra-storage/",
20,[],
[<0.16697.0>],
{[],[]}}
** Reason for termination ==
** killed
笔者更新CouchDB到2.1.1,便可以正常使用Replicator复制远程数据库。
3. 客户端
3.1 ACRA使用案例
-
首先,build.gradle中加入如下依赖:
dependencies { // ACRA(Application Crash Reporting on Android) implementation "ch.acra:acra-http:5.0.2" ... }
注意:笔者使用的是5.0.2版本,在接口使用上,与4.x的版本存在明显的不同。
-
然后,继承实现Application类,将@AcraHttpSender这个注解添加到自定义的类前面:
@AcraHttpSender( uri = "http://duanqz.gotunnel.net/acra-secure/_design/acra-storage/_update/report", httpMethod = HttpSender.Method.PUT, basicAuthLogin = "demo", basicAuthPassword = "123456" ) public class DemoApplication extends Application { }
@AcraHttpSender需要填入一些参数:uri表示服务端接收上报数据的地址,httpMethod可选的有POST和PUT,basicAuthLogin和basicAuthPassword用于上报的鉴权。这些参数值,其实就是在服务端Acralyzer创建一个用户时自动生成的,笔者上文创建的用户和密码demo/123456,就是此处需要填入的参数值。
注意,在ACRA 5.0之前的版本,使用的注解是@ReportCrashs,参数的Key也略有区别,譬如:@ReportCrashs的参数fromUri变成了@AcraHttpSender的uri。更多区别,请参见https://github.com/ACRA/acra/wiki/Migrating。
-
最后,重写Application类的attachBaseContext()方法,来完成ACRA的初始化:
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); ACRA.init(this); ACRA.getErrorReporter().handleSilentException(new Exception("I am exception.")); }
此处,调用了ACRA.init()完成了ACRA环境的初始化,其具体实现方式后文在做详细分析;之后,主动上报了一个异常I am exception,当应用程序启动时,就会将该异常上报到服务端。
通过以上三步,就完成了客户端上报异常的所有工作,在服务端看到上报的结果如下图:
除了异常信息,还有很多与设备相关的信息也会上报,在Full report一项中会呈现出来:
更多信息,请参考官方的ReportContent介绍。
4. 参考资料
- ACRA官方WIKI:https://github.com/ACRA/acra/wiki。
- Acra详细分析:https://www.jianshu.com/p/fd4d6a7c6175。分析了ACRA 4.9的代码逻辑,本文使用ACRA 5.0.2,ACRA并不是向前兼容的,接口使用上存在很大的不同。