• 保存错误日志回传服务器之回传错误“信息文件”


    主要源码:

    package com.demo.uploaderrorinfofile.common;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.PrintWriter;
    import java.lang.Thread.UncaughtExceptionHandler;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    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.uploaderrorinfofile.Utils.FileNameUtils;
    import com.demo.uploaderrorinfofile.Utils.FilePathUtils;
    import com.demo.uploaderrorinfofile.Utils.HttpClientUpLoadTask;
    import com.demo.uploaderrorinfofile.Utils.JsonUtils;
    import com.demo.uploaderrorinfofile.Utils.PackageManagerUtils;
    
    import android.content.Context;
    //import android.content.pm.PackageInfo;
    import android.text.format.DateFormat;
    import android.util.Log;
    
    /**
     * 在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);
            //得到错误信息所保存的文件的绝对路径
            String errorLogFilePath = this.saveToErrorLogFile(errorInfo);
            if(StringUtils.isNotBlank(errorLogFilePath)){
                Log.d(logTag, "error saved in file " + errorLogFilePath);
                
                //服务器的接口位置  yxg
    //          String url = URLFactory.getInstance(this.context).getServicesURL().getUploadErrorLogURL();
                  String url = "http://192.168.18.126:8080/test/upload";
                Map<String, Object> upLoadMsgFile=new HashMap<String, Object>();
                upLoadMsgFile.put("files",errorLogFilePath);
                
                //假如文件路径不为空,就将错误文件上传到服务器上
                 HttpClientUpLoadTask uploadFileTask = new HttpClientUpLoadTask();
                 uploadFileTask.execute(url,JsonUtils.toJson(upLoadMsgFile));
                 
                 String resultData;
                 try {
                     resultData = uploadFileTask.get();
                     uploadFileCallBack(resultData, errorLogFilePath);
                 } 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 String saveToErrorLogFile(String errorInfo){
            //错误文件的名字
            String fileName = CrashHandler.this.genErrorFileName();
            //错误文件的目录
            String fileDir = CrashHandler.this.getLogDir();
            try {
                File errorLogFile = new File(fileDir, fileName);
                
                Log.d(CrashHandler.logTag, String.format("save error file is:%s", errorLogFile.getAbsolutePath()));
                //将错误信息写到文件里面
                PrintWriter pw = new PrintWriter(new FileOutputStream(errorLogFile,true));
                pw.println(errorInfo);
                pw.flush();
                pw.close();
                //getAbsolutePath()得到绝对路径、全路径
                return errorLogFile.getAbsolutePath();
            } catch (Exception e) {
                Log.e(logTag, "write file error.", e);
            }
            
            return null;
        }
      //错误文件的目录
        private String getLogDir(){
            String logDir = FilePathUtils.getFilePath(this.context);
            try {
                File logDirFile = new File(logDir);
                if (!logDirFile.exists()) {
                    logDirFile.mkdirs();
                    Log.d(logTag, String.format("make dir success<%s>", logDirFile.getAbsolutePath()));
                }
                Log.d(logTag, String.format("log dir is:%s", logDirFile.getAbsolutePath()));
            } catch (Exception e) {
                Log.e(logTag, "make dir error.", e);
            }
            return logDir;
        }
        
        //将app的名字作为错误文件的名字(包含错误时间)
        private String genErrorFileName(){
            String fileName = PackageManagerUtils.getInstance(this.context).getAppName();
            fileName += "-";
            fileName += "error";
            fileName += "-";
            fileName += FileNameUtils.genFileNameByDateTime();//获取当前的时间
            fileName += ".log";
            
            return fileName;
        }
        
        //根据服务器返回值判定是否上传成功。(resultCode==0表示上传成功)
        private final void uploadFileCallBack(String resultData, String  errorLogFilePath ){
            if(StringUtils.isBlank(resultData) || StringUtils.isBlank( errorLogFilePath)){
                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){
                File f = new File( errorLogFilePath);
                if(f.exists()){
                    f.delete();
                    Log.d(logTag, "delete errorlog file ok. "+  errorLogFilePath);
                }else{
                    Log.d(logTag, "errorlog file not exists. "+  errorLogFilePath);
                }
            }else{
                Log.d(logTag, "uploadFileCallBack resultCode=" + resultCode);
            }
        }
    }
    我是刚刚进入公司的Android实习生,菜鸟一枚,博客记录我犯过的错,收获的东西,学到的知识和技术,可能里面会有很多错误的地方,幼稚的地方,欢迎大家指出来,帮助我进步,但请别伤害我,我只是菜鸟一枚,我在努力争取进步。
  • 相关阅读:
    哎~水题,还是最小生成树。没想到一遍AC了...
    博客搬家咯~
    又遇到一个奇葩问题....输出double用%f...
    又想吐槽一下了...同样是DP,差别咋就那么大呢?
    1487: 未覆盖顶点数量.
    并查集~
    侃项目管理 序
    安装Redis报错jemalloc/jemalloc.h: No such file or directory
    PyCharm设置pip国内源(镜像)
    HBase元数据及损坏文件的修复
  • 原文地址:https://www.cnblogs.com/smilefortoday/p/3974478.html
Copyright © 2020-2023  润新知