android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地

http://blog.csdn.net/jason0539/article/details/45602655

应用发生crash之后要查看log,判断问题出在什么地方,可是一旦应用发布出去,就要想办法把用户的崩溃日志拿到分析。

所以要在发生crash之后抓取log,然后上传到服务器,方便开发者查看,现在都有很多第三方做这方面的服务,这里说下如何自己来实现。

其实原理很简单,应用出现异常后,会由默认的异常处理器来处理异常,

我们要做的就是把这个任务接管过来,自己处理异常,包括收集日志,保存到本地,然后上传到服务器。

下面是自己实现的异常处理类。

[java] view plain copy

print?

  1. public class CrashHandler implements UncaughtExceptionHandler {
  2. public static final String TAG = "CrashHandler";
  3. // 系统默认的UncaughtException处理类
  4. private Thread.UncaughtExceptionHandler mDefaultHandler;
  5. // CrashHandler实例
  6. private static CrashHandler INSTANCE = new CrashHandler();
  7. // 程序的Context对象
  8. private Context mContext;
  9. // 用来存储设备信息和异常信息
  10. private Map<String, String> infos = new HashMap<String, String>();
  11. // 用于格式化日期,作为日志文件名的一部分
  12. private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
  13. private String nameString;
  14. /** 保证只有一个CrashHandler实例 */
  15. private CrashHandler() {
  16. }
  17. /** 获取CrashHandler实例 ,单例模式 */
  18. public static CrashHandler getInstance() {
  19. return INSTANCE;
  20. }
  21. /**
  22. * 初始化
  23. *
  24. * @param context
  25. */
  26. public void init(Context context) {
  27. mContext = context;
  28. // 获取系统默认的UncaughtException处理器
  29. mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
  30. // 设置该CrashHandler为程序的默认处理器
  31. Thread.setDefaultUncaughtExceptionHandler(this);
  32. nameString = BmobUserManager.getInstance(mContext).getCurrentUserName();
  33. }
  34. /**
  35. * 当UncaughtException发生时会转入该函数来处理
  36. */
  37. @Override
  38. public void uncaughtException(Thread thread, Throwable ex) {
  39. if (!handleException(ex) && mDefaultHandler != null) {
  40. // 如果用户没有处理则让系统默认的异常处理器来处理
  41. mDefaultHandler.uncaughtException(thread, ex);
  42. } else {
  43. try {
  44. Thread.sleep(3000);
  45. } catch (InterruptedException e) {
  46. Log.e(TAG, "error : ", e);
  47. }
  48. // 退出程序
  49. android.os.Process.killProcess(android.os.Process.myPid());
  50. System.exit(1);
  51. }
  52. }
  53. /**
  54. * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
  55. *
  56. * @param ex
  57. * @return true:如果处理了该异常信息;否则返回false.
  58. */
  59. private boolean handleException(Throwable ex) {
  60. if (ex == null) {
  61. return false;
  62. }
  63. WonderMapApplication.getInstance().getSpUtil().setCrashLog(true);// 每次进入应用检查,是否有log,有则上传
  64. // 使用Toast来显示异常信息
  65. new Thread() {
  66. @Override
  67. public void run() {
  68. Looper.prepare();
  69. Toast.makeText(mContext, "很抱歉,程序出现异常,正在收集日志,即将退出", Toast.LENGTH_LONG)
  70. .show();
  71. Looper.loop();
  72. }
  73. }.start();
  74. // 收集设备参数信息
  75. collectDeviceInfo(mContext);
  76. // 保存日志文件
  77. String fileName = saveCrashInfo2File(ex);
  78. return true;
  79. }
  80. /**
  81. * 收集设备参数信息
  82. *
  83. * @param ctx
  84. */
  85. public void collectDeviceInfo(Context ctx) {
  86. try {
  87. PackageManager pm = ctx.getPackageManager();
  88. PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
  89. PackageManager.GET_ACTIVITIES);
  90. if (pi != null) {
  91. String versionName = pi.versionName == null ? "null"
  92. : pi.versionName;
  93. String versionCode = pi.versionCode + "";
  94. infos.put("versionName", versionName);
  95. infos.put("versionCode", versionCode);
  96. }
  97. } catch (NameNotFoundException e) {
  98. Log.e(TAG, "an error occured when collect package info", e);
  99. }
  100. Field[] fields = Build.class.getDeclaredFields();
  101. for (Field field : fields) {
  102. try {
  103. field.setAccessible(true);
  104. infos.put(field.getName(), field.get(null).toString());
  105. Log.d(TAG, field.getName() + " : " + field.get(null));
  106. } catch (Exception e) {
  107. Log.e(TAG, "an error occured when collect crash info", e);
  108. }
  109. }
  110. }
  111. /**
  112. * 保存错误信息到文件中
  113. *
  114. * @param ex
  115. * @return 返回文件名称,便于将文件传送到服务器
  116. */
  117. private String saveCrashInfo2File(Throwable ex) {
  118. StringBuffer sb = new StringBuffer();
  119. for (Map.Entry<String, String> entry : infos.entrySet()) {
  120. String key = entry.getKey();
  121. String value = entry.getValue();
  122. sb.append(key + "=" + value + "\n");
  123. }
  124. Writer writer = new StringWriter();
  125. PrintWriter printWriter = new PrintWriter(writer);
  126. ex.printStackTrace(printWriter);
  127. Throwable cause = ex.getCause();
  128. while (cause != null) {
  129. cause.printStackTrace(printWriter);
  130. cause = cause.getCause();
  131. }
  132. printWriter.close();
  133. String result = writer.toString();
  134. L.d(WModel.CrashUpload, result);
  135. sb.append(result);
  136. try {
  137. long timestamp = System.currentTimeMillis();
  138. String time = formatter.format(new Date());
  139. String fileName = nameString + "-" + time + "-" + timestamp
  140. + ".log";
  141. if (Environment.getExternalStorageState().equals(
  142. Environment.MEDIA_MOUNTED)) {
  143. String path = WMapConstants.CrashLogDir;
  144. File dir = new File(path);
  145. if (!dir.exists()) {
  146. dir.mkdirs();
  147. }
  148. FileOutputStream fos = new FileOutputStream(path + fileName);
  149. fos.write(sb.toString().getBytes());
  150. fos.close();
  151. }
  152. return fileName;
  153. } catch (Exception e) {
  154. Log.e(TAG, "an error occured while writing file...", e);
  155. }
  156. return null;
  157. }
  158. }

使用方式如下:

在Application的onCreate中加上下面

[java] view plain copy

print?

  1. CrashHandler crashHandler = CrashHandler.getInstance();
  2. crashHandler.init(this);

这样一来,应用发生crash,自动保存log到本地了。

其实这样还有一个好处,就是不用在logcat里面翻来翻去找日志,直接到本地文件夹打开看就是了。

时间: 2024-10-08 21:25:19

android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地的相关文章

IIS崩溃时自动抓取Dump

背景:在客户现场,IIS有时会崩溃,开发环境没法重现这个bug,唯有抓取IIS的崩溃是的Dump文件分析. IIS崩溃时自动抓取Dump,需要满足下面几个条件 1.启动 Windows Error Reporting Service 服务 2.移除默认的调试器 如果你的机器装了VS开发工具,会在注册表里写入调试器地址,需要把它删除. 找到注册表删除以下2个项目HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDeb

自动抓取163新闻的Python爬虫源码

Python爬虫的学习,自动抓取163新闻的Python爬虫源码,这是一个用Python语言编写的,自动抓取网易新闻的python爬虫实现方法一文. Python爬虫的抓取思路是:(1)通过分析目标新闻网址 ,分析其中以News.xxx.com 开头的链接(2)获取每一个链接的内容,并做整理合并到事前准备好的.txt 文本中,以便查看各新闻.但是需要注意的是:由于今天的测试对象,网易新闻的格式不是非常统一,所有会有部分漏掉的情况,还能大家见谅.也希望有能力的朋友们帮着改进一下. 自动抓取163新

scrapy自动抓取蛋壳公寓最新房源信息并存入sql数据库

利用scrapy抓取蛋壳公寓上的房源信息,以北京市为例,目标url:https://www.dankegongyu.com/room/bj 思路分析 每次更新最新消息,都是在第一页上显示,因此考虑隔一段时间自动抓取第一页上的房源信息,实现抓取最新消息. 利用redis的set数据结构的特征,将每次抓取后的url存到redis中: 每次请求,将请求url与redis中的url对比,若redis中已存在该url,代表没有更新,忽略该次请求:若redis中不存在该url,代表该信息是新信息,抓取并将u

iOS Crash 分析(文三)- 符号化崩溃日志

iOS Crash 分析(文三)- 符号化崩溃日志 未符号化的崩溃日志就象一本天书,看不懂,更别谈分析崩溃原因了.所以我们在分析日志之前,要把日志翻译成我们可以看得懂的文字.这一步我们称之为符号化. 在iOS Crash分析(文一)中已经提到过符号化的两种方式: 1.利用Xcode符号化 2.利用symbolicatecrash脚本符号化 其实这两种分析方式都使用了同一个工具符号化:***atos***. atos是苹果提供的符号化工具,在Mac OS系统下默认安装. 使用***atos***符

Windows Phone &amp; Windows App应用程序崩溃crash信息抓取方法

最近有用户反馈,应用有崩溃的情况,可是本地调试却无法重现问题,理所当然的,我想到了微软的开发者仪表盘,可以查看一段时间内的carsh记录,不过仪表盘生成carsh记录不是实时的,而且生成的报告查看非常不便,是否有其他方法抓取应用的崩溃记录呢? 其实目前已经有一些第三方提供了相应的工具插件,如国外的uTest(http://www.utest.com/),mtiks(http://www.mtiks.com/),国内的九幽(http://www.windows.sc)等等,小弟英语比较烂,就只研究

Eclipse+Android开发环境搭建失败--R文件出错,自动新建Android application project 出错。

Eclipse : Mars.2 Release (4.5.2)  + Android6.0(api23)以上的tools,SDK,以及相关的Extras   +  ADT 23.0.6,我都装了.   由于是初学者,一开始去官网准备各种资源. 上面是现在的android官网 和  google推荐使用的 android studio ,基本上已经看不到sdk完整包的下载了. 我是从网上下的旧版本的sdk包,然后一开始用的最新的ADT(23.0.7),然后我再通过android manager

charles抓取线上接口数据替换为本地json格式数据

最近要做下拉刷新,无奈测试服务器的测试数据太少,没有足够的数据做下拉刷新,所以用charles抓取了测试服务器的接口,然后在伪造了很多数据返回到我的电脑上,下面来说说使用方法: 第一步: 安装FQ软件 XX-net,这个自己去百度安装方法,切换连接方式为系统代理,如下图: 第二步:以window为例,让charles支持跨域 打开charles软件 - > proxy菜单栏 -> 勾选windows proxy -> Flie菜单栏 -> New Session ->刷新你的

抓取数据,保存到表格

网上看房子,不过网速太慢,就做个demo来抓数据并存到表格里. 代码如下: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using HtmlAgilityPack; using System.Data; using System.Reflec

Python开发爬虫之动态网页抓取篇:爬取博客评论数据

以爬取<Python 网络爬虫:从入门到实践>一书作者的个人博客评论为例.网址:http://www.santostang.com/2017/03/02/hello-world/ 1)"抓包":找到真实的数据地址 右键点击"检查",点击"network",选择"js".刷新一下页面,选中页面刷新时返回的数据list?callback....这个js文件.右边再选中Header.如图: 其中,Request URL即