保存错误日志回传服务器之回传错误“信息”
近期领导交给我个任务,即已经上线的一个android产品出现Bug,但只是个别手机出现Bug,主流手机都没事,但是我们不可能把所有出现问题的手机都搜集过来测试开发(实际上出现问题的手机都比较难拿到机型,例如:红米定制版,索尼等),因此只能想个办法:在项目中加上保存错误日志,并将错误信息回传到服务器的方法,然后通过错误日志分析Bug,因此我在参考了网上的一些解决方案后,自己修改写了两种方式:一、直接将错误信息+手机信息发送到服务器 二、将错误信息+手机信息保存到一个文件,将文件上传到服务器。不过说实话,这些还没试验过,不知道能不能用,暂且先写出来,以后有问题再修改:
参考文章:
1.http://www.jb51.net/article/41112.htm
2.http://www.cnblogs.com/stay/archive/2011/07/21/2113167.html
3.http://onewayonelife.iteye.com/blog/1147533
4.http://chenkechao123.blog.163.com/blog/static/1383326482012924238251/
源码:
package com.demo.uploaderrorinfo.common; import java.lang.Thread.UncaughtExceptionHandler; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.map.CaseInsensitiveMap; import org.apache.commons.lang.StringUtils; import com.demo.uploaderrorinfo.Utils.HttpClientUpLoadTask; import com.demo.uploaderrorinfo.Utils.JsonUtils; import com.demo.uploaderrorinfo.Utils.PackageManagerUtils; import android.content.Context; //import android.content.pm.PackageInfo; import android.text.format.DateFormat; import android.util.Log; /** * @author LHG<br/> * 在Application中统一捕获异常,并上传到服务器上 * 自定义异常类实现UncaughtExceptionHandler接口,当某个页面出现 * 异常就会调用uncaughtException这个方法,我们可以在这个方法中获取 * 异常信息、时间等,然后将获取到的信息发送到我们指定的服务器 */ public class CrashHandler implements UncaughtExceptionHandler { private static final String logTag = CrashHandler.class.getSimpleName(); // private PackageInfo packageInfo; /** 系统默认的UncaughtException处理类 */ private Thread.UncaughtExceptionHandler defaultHandler; /** CrashHandler实例 */ private static CrashHandler INSTANCE; /** 程序的Context对象 */ private Context context; /** 保证只有一个CrashHandler实例 */ private CrashHandler() {} /** 获取CrashHandler实例 ,单例模式*/ public static CrashHandler getInstance() { if (INSTANCE == null) { INSTANCE = new CrashHandler(); } return INSTANCE; } /** * 初始化,注册Context对象, * 获取系统默认的UncaughtException处理器, * 设置该CrashHandler为程序的默认处理器 * * @param ctx */ public void register(Context ctx) { this.context = ctx; //获取默认的handler defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); //设置自己的handler Thread.setDefaultUncaughtExceptionHandler(this); } /** * 当UncaughtException发生时会转入该函数来处理 */ @Override public void uncaughtException(Thread thread, Throwable ex) { Log.d(logTag, "Now enter CrashHandler. In somewhere occur error. I try to save the error."); boolean isProcessed = handleException(thread, ex); if (!isProcessed && defaultHandler != null) { //如果用户没有处理则让系统默认的异常处理器来处理 defaultHandler.uncaughtException(thread, ex); } else { //如果自己处理了异常,则不会弹出错误对话框,则需要手动退出程序 try { Thread.sleep(3000); } catch (InterruptedException e) { } //干掉自己 android.os.Process.killProcess(android.os.Process.myPid()); //退出程序 System.exit(10); } } /** * 自定义错误处理,收集错误信息 * 发送错误报告等操作均在此完成. * true代表处理该异常,不再向上抛异常, * false代表不处理该异常(可以将该log信息存储起来)然后交给上层(这里就到了系统的异常处理)去处理, * 简单来说就是true不会弹出那个错误提示框,false就会弹出 */ private boolean handleException(final Thread thread, final Throwable ex) { if (ex == null) { Log.d(logTag, "no exception info."); return false; } //得到详细的错误信息 final String errorInfo = this.getErrorInfo(ex); Log.d(logTag, errorInfo); if(StringUtils.isNotBlank(errorInfo)){ Log.d(logTag, "error saved in file " + errorInfo); //服务器的接口 // String url = URLFactory.getInstance(this.context).getServicesURL().getUploadErrorLogURL(); String url = "http://192.168.18.126:8080/test/upload"; //将保存的错误信息上传到服务器 HttpClientUpLoadTask uploadFileTask = new HttpClientUpLoadTask(); uploadFileTask.execute(url, errorInfo); String resultData; try { resultData = uploadFileTask.get(); uploadFileCallBack(resultData); } catch (Exception e) { e.printStackTrace(); } } return false; } //获取详细的错误信息、应用程序的信息、手机型号版本 private String getErrorInfo(Throwable ex) { List<String> errorContents = new ArrayList<String>(); StackTraceElement[] sts = ex.getStackTrace();//获取错误代码的位置和信息 if(null != sts){ for(StackTraceElement st : sts){ if(null != st && null != st.toString()){ errorContents.add(st.toString()); } } } @SuppressWarnings("unchecked") Map<String,Object> errorInfoMap = new CaseInsensitiveMap(); //发生错误的时间 errorInfoMap.put("errortime", DateFormat.format("yyyy-MM-dd kk:mm:ss", new Date(System.currentTimeMillis()))); //手机型号 errorInfoMap.put("phonetype", android.os.Build.MODEL); errorInfoMap.put("androidsdkversion", android.os.Build.VERSION.SDK); errorInfoMap.put("androidreleaseversion", android.os.Build.VERSION.RELEASE); String localVersion =PackageManagerUtils.getInstance(this.context).getVersionName(); errorInfoMap.put("appversion", localVersion); errorInfoMap.put("errormessage", ex.getMessage()); errorInfoMap.put("errorcontent", errorContents); //上面得到的错误信息 (String) return JsonUtils.toJson(errorInfoMap); } private final void uploadFileCallBack(String resultData){ if(StringUtils.isBlank(resultData) ){ Log.d(logTag, "uploadFileCallBack occur error."); return; } Log.d(logTag, "uploadFileCallBack receive resultData: "+ resultData); Map resultMap = JsonUtils.fromJsonToCaseInsensitiveMap(resultData); int resultCode = MapUtils.getIntValue(resultMap, "resultCode", -1); if(0 == resultCode){ Log.d(logTag, "successful. "); }else{ Log.d(logTag, "false "); } } }
这些是主要的源码,一些辅助性的代码和项目文件等我学会怎么上传博客中后,就直接放项目了!
下面一篇文章是介绍怎么把 “错误信息和手机信息保存成文件上传服务器”的源码
我是刚刚进入公司的Android实习生,菜鸟一枚,博客记录我犯过的错,收获的东西,学到的知识和技术,可能里面会有很多错误的地方,幼稚的地方,欢迎大家指出来,帮助我进步,但请别伤害我,我只是菜鸟一枚,我在努力争取进步。