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

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

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

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

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

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

  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中加上下面

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

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

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

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

  1. APP自动化框架LazyAndroid使用手册(2)--元素自动抓取

    作者:黄书力 概述 前面的一篇博文简要介绍了安卓自动化测试框架LazyAndroid的组成结构和基本功能,本文将详细描述此框架中元素自动抓取工具lazy-uiautomaterviewer的使用方法. ...

  2. SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享

    SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...

  3. IIS崩溃时自动抓取Dump

    背景:在客户现场,IIS有时会崩溃,开发环境没法重现这个bug,唯有抓取IIS的崩溃是的Dump文件分析. IIS崩溃时自动抓取Dump,需要满足下面几个条件 1.启动 Windows Error R ...

  4. 学习笔记CB010:递归神经网络、LSTM、自动抓取字幕

    递归神经网络可存储记忆神经网络,LSTM是其中一种,在NLP领域应用效果不错. 递归神经网络(RNN),时间递归神经网络(recurrent neural network),结构递归神经网络(recu ...

  5. 巧用Grafana和Arthas自动抓取K8S中异常Java进程的线程堆栈

    前言 近期发现业务高峰期时刻会出现CPU繁忙导致的timeout异常,通过监控来看是因为Node上面的一些Pod突发抢占了大量CPU导致的. 问: 没有限制CPU吗?是不是限制的CPU使用值就可以解决 ...

  6. 自动抓取java堆栈

    参数1 进程名字,参数2 最大线程数 例: pid为8888,达到1000个线程时自动抓取堆栈信息 ./autojstack.sh 8888 1000 & #!/bin/bashfileNam ...

  7. SQL Server定时自动抓取耗时SQL并归档数据脚本分享

    原文:SQL Server定时自动抓取耗时SQL并归档数据脚本分享 SQL Server定时自动抓取耗时SQL并归档数据脚本分享 第一步建库 USE [master] GO CREATE DATABA ...

  8. 【VIP视频网站项目】VIP视频网站项目v1.0.3版本发布啦(程序一键安装+电影后台自动抓取+代码结构调整)

    在线体验地址:http://vip.52tech.tech/ GIthub源码:https://github.com/xiugangzhang/vip.github.io 项目预览 主页面 登录页面 ...

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

    利用scrapy抓取蛋壳公寓上的房源信息,以北京市为例,目标url:https://www.dankegongyu.com/room/bj 思路分析 每次更新最新消息,都是在第一页上显示,因此考虑隔一 ...

随机推荐

  1. HDU 2647

    思路:拓扑排序 #include<stdio.h> #include<string.h> typedef struct { int to; int next; }EdgeNod ...

  2. Linux中的权限管理

    touch 11.txt(创建了一个文件) chown zhangsan:zhangsan 11.txt ll(可看到11.txt的属主和属组都改为了zhangsan) useradd lisi(添加 ...

  3. java中的hashtable

    好久没写博客了,这次总结一下hashtable,哈希表是我们在数据结构时候所学,在网络安全时候,老师说可以用来加密,在数据库中,可以用来当作索引. http://www.cnblogs.com/leo ...

  4. 输入A和B,计算并输出A+B

    EOF是一个预定义的常量,等于-1. 输入A和B,计算并输出A+B Sample input: 1    5 10  20 Sample output: 6 30 #include <iostr ...

  5. java中String、StringBuilder、StringBuffer三者的区别

    在Java项目开发中,字符串是最长使用的数据类型,而有关字符串的String.StringBuilder.StringBuffer三者又常常让人分不清楚什么时候该使用哪个. 特此整理一下. Strin ...

  6. Solution for When browse http://xxx/ReportServer Show Error (rsAccessDenied)

    Issue: Reporting Services Error The permissions granted to user 'IDEAAM\William' are insufficient fo ...

  7. Java 解析epub格式电子书,helloWorld程序,附带源程序和相关jar包

    秀才坤坤出品 一.epub格式电子书 相关材料和源码均在链接中可以下载:http://pan.baidu.com/s/1bnm8YXT 包括 1.JAVA项目工程test_epub,里面包括了jar包 ...

  8. UVa 497 - Strategic Defense Initiative

    题目:最大上升子序列.输出一组解. 分析:dp,LIS.数据较小 O(n^2)算法就可以. 设以第i个数字作为最大上升子序列中的最后一个数的长度为 f(i),则有转移方程: f(i)= max(f(j ...

  9. Oracle基础学习1--Oracle安装

    安装过程较简单.按着步骤走就可以.这里须要提醒假设要使用PL/SQL来操作Oracle.那么最好安装32位Oracle程序.原因是网上说PL/SQL仅仅对32位Oracle进行支持,假设用64为Ora ...

  10. android webview内容压线问题解决方法

    最近在使用webview做页面开发,项目上要求webview在获取到焦点的时候需要有边框线,于是添加上了webview的选中效果,但是出现了网页中的内容压选中框的情况.之后给webview添加padd ...