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. xampp 访问出现New XAMPP security concept 或者 新しいXAMPPのセキュリティコンセプト

    出现如下错误: 新しいXAMPPのセキュリティコンセプト: は.要求されたオブジェクトへのアクセスは.ローカルネットワークから入手可能です. この設定は.ファイル"で設定することができますの ...

  2. iOS开发——View的透明属性hidden、alpha、opaque

    Hidden.Alpha.Opaque的区别 在iOS中,每个View都有Hidden.Alpha.Opaque三个关于透明的属性,官方文档介绍如下: 1. @property(nonatomic) ...

  3. 使用Cross-validation (CV) 调整Extreme learning Machine (ELM) 最优参数的实现(matlab)

    ELM算法模型是最近几年得到广泛重视的模型,它不同于现在广为火热的DNN. ELM使用传统的三层神经网络,只包含一个隐含层,但又不同于传统的神经网络.ELM是一种简单易用.有效的单隐层前馈神经网络SL ...

  4. ACM编程技巧--常用字符操作函数

    字符串与基本数据类型的转换 int sscanf(buff,"%d%d",&a,&b); //返回值是参数个数 int sprintf(buff,"%d% ...

  5. POJ1947 - Rebuilding Roads(树形DP)

    题目大意 给定一棵n个结点的树,问最少需要删除多少条边使得某棵子树的结点个数为p 题解 很经典的树形DP~~~直接上方程吧 dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v] ...

  6. python —print

    今天开始学python了,“装X”安装了最新版本python 3.4.1 然后,print “hello world!" 就出错了... 一搜原来... python v3.0以后的版本pr ...

  7. js基础一

    1.声明提升:变量的声明提升,函数的声明提升,但函数赋值表达式不会提升: foo(); // 正常运行,因为foo在代码运行前已经被创建 function foo() {} foo(); // 出错: ...

  8. Brief描述子

    一.Brief算法 1.基本原理 BRIEF是2010年的一篇名为<BRIEF:Binary Robust Independent Elementary Features>的文章中提出,B ...

  9. Spring3.0 AOP 具体解释

    一.什么是 AOP. AOP(Aspect Orient Programming),也就是面向切面编程.能够这样理解,面向对象编程(OOP)是从静态角度考虑程序结构,面向切面编程(AOP)是从动态角度 ...

  10. \\ip 映射 指定的网络名不再可用

    问题:\\ip 映射  指定的网络名不再可用 解决方法:服务器端打开服务列表  services.msc 启动两个进程 1.Computer Browser 2. Workstation 就正常了~~ ...