android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地
http://blog.csdn.net/jason0539/article/details/45602655
应用发生crash之后要查看log,判断问题出在什么地方,可是一旦应用发布出去,就要想办法把用户的崩溃日志拿到分析。
所以要在发生crash之后抓取log,然后上传到服务器,方便开发者查看,现在都有很多第三方做这方面的服务,这里说下如何自己来实现。
其实原理很简单,应用出现异常后,会由默认的异常处理器来处理异常,
我们要做的就是把这个任务接管过来,自己处理异常,包括收集日志,保存到本地,然后上传到服务器。
下面是自己实现的异常处理类。
- public class CrashHandler implements UncaughtExceptionHandler {
- public static final String TAG = "CrashHandler";
- // 系统默认的UncaughtException处理类
- private Thread.UncaughtExceptionHandler mDefaultHandler;
- // CrashHandler实例
- private static CrashHandler INSTANCE = new CrashHandler();
- // 程序的Context对象
- private Context mContext;
- // 用来存储设备信息和异常信息
- private Map<String, String> infos = new HashMap<String, String>();
- // 用于格式化日期,作为日志文件名的一部分
- private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
- private String nameString;
- /** 保证只有一个CrashHandler实例 */
- private CrashHandler() {
- }
- /** 获取CrashHandler实例 ,单例模式 */
- public static CrashHandler getInstance() {
- return INSTANCE;
- }
- /**
- * 初始化
- *
- * @param context
- */
- public void init(Context context) {
- mContext = context;
- // 获取系统默认的UncaughtException处理器
- mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- // 设置该CrashHandler为程序的默认处理器
- Thread.setDefaultUncaughtExceptionHandler(this);
- nameString = BmobUserManager.getInstance(mContext).getCurrentUserName();
- }
- /**
- * 当UncaughtException发生时会转入该函数来处理
- */
- @Override
- public void uncaughtException(Thread thread, Throwable ex) {
- if (!handleException(ex) && mDefaultHandler != null) {
- // 如果用户没有处理则让系统默认的异常处理器来处理
- mDefaultHandler.uncaughtException(thread, ex);
- } else {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- Log.e(TAG, "error : ", e);
- }
- // 退出程序
- android.os.Process.killProcess(android.os.Process.myPid());
- System.exit(1);
- }
- }
- /**
- * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
- *
- * @param ex
- * @return true:如果处理了该异常信息;否则返回false.
- */
- private boolean handleException(Throwable ex) {
- if (ex == null) {
- return false;
- }
- WonderMapApplication.getInstance().getSpUtil().setCrashLog(true);// 每次进入应用检查,是否有log,有则上传
- // 使用Toast来显示异常信息
- new Thread() {
- @Override
- public void run() {
- Looper.prepare();
- Toast.makeText(mContext, "很抱歉,程序出现异常,正在收集日志,即将退出", Toast.LENGTH_LONG)
- .show();
- Looper.loop();
- }
- }.start();
- // 收集设备参数信息
- collectDeviceInfo(mContext);
- // 保存日志文件
- String fileName = saveCrashInfo2File(ex);
- return true;
- }
- /**
- * 收集设备参数信息
- *
- * @param ctx
- */
- public void collectDeviceInfo(Context ctx) {
- try {
- PackageManager pm = ctx.getPackageManager();
- PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
- PackageManager.GET_ACTIVITIES);
- if (pi != null) {
- String versionName = pi.versionName == null ? "null"
- : pi.versionName;
- String versionCode = pi.versionCode + "";
- infos.put("versionName", versionName);
- infos.put("versionCode", versionCode);
- }
- } catch (NameNotFoundException e) {
- Log.e(TAG, "an error occured when collect package info", e);
- }
- Field[] fields = Build.class.getDeclaredFields();
- for (Field field : fields) {
- try {
- field.setAccessible(true);
- infos.put(field.getName(), field.get(null).toString());
- Log.d(TAG, field.getName() + " : " + field.get(null));
- } catch (Exception e) {
- Log.e(TAG, "an error occured when collect crash info", e);
- }
- }
- }
- /**
- * 保存错误信息到文件中
- *
- * @param ex
- * @return 返回文件名称,便于将文件传送到服务器
- */
- private String saveCrashInfo2File(Throwable ex) {
- StringBuffer sb = new StringBuffer();
- for (Map.Entry<String, String> entry : infos.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- sb.append(key + "=" + value + "\n");
- }
- Writer writer = new StringWriter();
- PrintWriter printWriter = new PrintWriter(writer);
- ex.printStackTrace(printWriter);
- Throwable cause = ex.getCause();
- while (cause != null) {
- cause.printStackTrace(printWriter);
- cause = cause.getCause();
- }
- printWriter.close();
- String result = writer.toString();
- L.d(WModel.CrashUpload, result);
- sb.append(result);
- try {
- long timestamp = System.currentTimeMillis();
- String time = formatter.format(new Date());
- String fileName = nameString + "-" + time + "-" + timestamp
- + ".log";
- if (Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED)) {
- String path = WMapConstants.CrashLogDir;
- File dir = new File(path);
- if (!dir.exists()) {
- dir.mkdirs();
- }
- FileOutputStream fos = new FileOutputStream(path + fileName);
- fos.write(sb.toString().getBytes());
- fos.close();
- }
- return fileName;
- } catch (Exception e) {
- Log.e(TAG, "an error occured while writing file...", e);
- }
- return null;
- }
- }
使用方式如下:
在Application的onCreate中加上下面
- CrashHandler crashHandler = CrashHandler.getInstance();
- crashHandler.init(this);
这样一来,应用发生crash,自动保存log到本地了。
其实这样还有一个好处,就是不用在logcat里面翻来翻去找日志,直接到本地文件夹打开看就是了。
android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地的更多相关文章
- APP自动化框架LazyAndroid使用手册(2)--元素自动抓取
作者:黄书力 概述 前面的一篇博文简要介绍了安卓自动化测试框架LazyAndroid的组成结构和基本功能,本文将详细描述此框架中元素自动抓取工具lazy-uiautomaterviewer的使用方法. ...
- SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享
SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...
- IIS崩溃时自动抓取Dump
背景:在客户现场,IIS有时会崩溃,开发环境没法重现这个bug,唯有抓取IIS的崩溃是的Dump文件分析. IIS崩溃时自动抓取Dump,需要满足下面几个条件 1.启动 Windows Error R ...
- 学习笔记CB010:递归神经网络、LSTM、自动抓取字幕
递归神经网络可存储记忆神经网络,LSTM是其中一种,在NLP领域应用效果不错. 递归神经网络(RNN),时间递归神经网络(recurrent neural network),结构递归神经网络(recu ...
- 巧用Grafana和Arthas自动抓取K8S中异常Java进程的线程堆栈
前言 近期发现业务高峰期时刻会出现CPU繁忙导致的timeout异常,通过监控来看是因为Node上面的一些Pod突发抢占了大量CPU导致的. 问: 没有限制CPU吗?是不是限制的CPU使用值就可以解决 ...
- 自动抓取java堆栈
参数1 进程名字,参数2 最大线程数 例: pid为8888,达到1000个线程时自动抓取堆栈信息 ./autojstack.sh 8888 1000 & #!/bin/bashfileNam ...
- SQL Server定时自动抓取耗时SQL并归档数据脚本分享
原文:SQL Server定时自动抓取耗时SQL并归档数据脚本分享 SQL Server定时自动抓取耗时SQL并归档数据脚本分享 第一步建库 USE [master] GO CREATE DATABA ...
- 【VIP视频网站项目】VIP视频网站项目v1.0.3版本发布啦(程序一键安装+电影后台自动抓取+代码结构调整)
在线体验地址:http://vip.52tech.tech/ GIthub源码:https://github.com/xiugangzhang/vip.github.io 项目预览 主页面 登录页面 ...
- scrapy自动抓取蛋壳公寓最新房源信息并存入sql数据库
利用scrapy抓取蛋壳公寓上的房源信息,以北京市为例,目标url:https://www.dankegongyu.com/room/bj 思路分析 每次更新最新消息,都是在第一页上显示,因此考虑隔一 ...
随机推荐
- HDU 2647
思路:拓扑排序 #include<stdio.h> #include<string.h> typedef struct { int to; int next; }EdgeNod ...
- Linux中的权限管理
touch 11.txt(创建了一个文件) chown zhangsan:zhangsan 11.txt ll(可看到11.txt的属主和属组都改为了zhangsan) useradd lisi(添加 ...
- java中的hashtable
好久没写博客了,这次总结一下hashtable,哈希表是我们在数据结构时候所学,在网络安全时候,老师说可以用来加密,在数据库中,可以用来当作索引. http://www.cnblogs.com/leo ...
- 输入A和B,计算并输出A+B
EOF是一个预定义的常量,等于-1. 输入A和B,计算并输出A+B Sample input: 1 5 10 20 Sample output: 6 30 #include <iostr ...
- java中String、StringBuilder、StringBuffer三者的区别
在Java项目开发中,字符串是最长使用的数据类型,而有关字符串的String.StringBuilder.StringBuffer三者又常常让人分不清楚什么时候该使用哪个. 特此整理一下. Strin ...
- Solution for When browse http://xxx/ReportServer Show Error (rsAccessDenied)
Issue: Reporting Services Error The permissions granted to user 'IDEAAM\William' are insufficient fo ...
- Java 解析epub格式电子书,helloWorld程序,附带源程序和相关jar包
秀才坤坤出品 一.epub格式电子书 相关材料和源码均在链接中可以下载:http://pan.baidu.com/s/1bnm8YXT 包括 1.JAVA项目工程test_epub,里面包括了jar包 ...
- UVa 497 - Strategic Defense Initiative
题目:最大上升子序列.输出一组解. 分析:dp,LIS.数据较小 O(n^2)算法就可以. 设以第i个数字作为最大上升子序列中的最后一个数的长度为 f(i),则有转移方程: f(i)= max(f(j ...
- Oracle基础学习1--Oracle安装
安装过程较简单.按着步骤走就可以.这里须要提醒假设要使用PL/SQL来操作Oracle.那么最好安装32位Oracle程序.原因是网上说PL/SQL仅仅对32位Oracle进行支持,假设用64为Ora ...
- android webview内容压线问题解决方法
最近在使用webview做页面开发,项目上要求webview在获取到焦点的时候需要有边框线,于是添加上了webview的选中效果,但是出现了网页中的内容压选中框的情况.之后给webview添加padd ...