1. 程式人生 > >全域性異常捕捉並上傳log到伺服器

全域性異常捕捉並上傳log到伺服器

一個專案的完工後,我們也應給APP加上全域性的異常捕捉,並將異常log上傳到伺服器。有些朋友可能會遇到這樣的問題,異常是捕捉到了,但是還沒等到上傳到伺服器上APP就掛了。下面我們一起來看一下我在應用中的使用。



import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import com.wish.becomeeasy.activity.MainActivity;
import com.wish.becomeeasy.constant.Constant;
import com.wish.becomeeasy.utils.MyUtils;

/**
 * 
 * @類名稱: 	CrashHandler.java
 * @建立人:	Mr.ladeng (
[email protected]
) * @建立時間: 2015-8-14下午1:22:15 * @修改備註: * @version 1.0 * @類描述:捕捉全域性異常類 * * 在application類中onCreate下呼叫 * * CrashHandler crashHandler = CrashHandler.getInstance(); * crashHandler.init(getApplicationContext()); * */ 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 path; /** 證只有一個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); } /** * 當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; } //收集裝置引數資訊 collectDeviceInfo(mContext); //儲存日誌檔案 String crashInfoFile = saveCrashInfo2File(ex); // String substring = crashInfoFile.substring(0, crashInfoFile.indexOf("."));//去後綴 final List<File> crashFile = new ArrayList<File>(); File file = new File(path+crashInfoFile); crashFile.add(file); Log.e(TAG, path+crashInfoFile); //使用Toast來顯示異常資訊 new Thread() { @Override public void run() { Looper.prepare(); MyUtils.showToast(mContext, "親!讓我休息一下吧!"); String uploadMessage = UploadMessage(CrashHandler.this, "crashExp" , crashFile ); if (uploadMessage.equals("success")) { Log.e(TAG, "上傳日誌成功!"); }else { Log.e(TAG, "上傳日誌失敗!"); } Looper.loop(); } }.start(); Intent intent = new Intent(mContext , MainActivity.class); PendingIntent restartIntent = PendingIntent.getActivity(mContext.getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK); //退出程式 AlarmManager mgr = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒鐘後重啟應用 // mContext.finishActivity(); 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(); sb.append(result); try { long timestamp = System.currentTimeMillis(); String time = formatter.format(new Date()); String fileName = "crash-" + time + "-" + timestamp + ".log"; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { path = "/sdcard/crash/"; 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; } /***************** 把捕捉的異常傳送給伺服器 *********************/ public String UploadMessage(CrashHandler crashHandler, String crashExp , List<File> files) { HttpParams connParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(connParams, 5 * 1000); HttpConnectionParams.setSoTimeout(connParams, 5 * 1000); HttpClient client = new DefaultHttpClient(connParams); /*** HttpClient client=new DefaultHttpClient();// 開啟一個客戶端 HTTP 請求**/ /** 建立 HTTP POST請求*/ /** 請求地址 ***/ HttpPost post = new HttpPost("異常介面"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); /** 設定瀏覽器相容模式**/ builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); /** 新增檔案,新增的是實體內容 */ for (File file : files) { /*** 把檔案轉換成流物件FileBody***/ FileBody fileBody = new FileBody(file); builder.addPart("errorLog" , fileBody); } /*** 新增文字內容,後面要新增格式 ***/ // try { // builder.addPart("crashExp",new StringBody(crashExp, Charset.forName("UTF-8"))); // } catch (UnsupportedEncodingException e1) { // e1.printStackTrace(); // } /** 生成 HTTP POST 實體**/ HttpEntity entity = builder.build(); /** 設定請求引數***/ post.setEntity(entity); try { /***client.execute(post);//發起請求 並返回請求的響應**/ HttpResponse response = client.execute(post); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity json = response.getEntity(); if (json != null) { String data = EntityUtils.toString(json, "utf-8").trim(); JSONObject jsonObject = new JSONObject(data); String flag = jsonObject.getString("flag"); if (flag.equals("1")) { return "success"; } } } } catch (Exception e) { Log.e(TAG, e.getMessage()); } return ""; } }
還是上程式碼比較實在。網上的異常捕捉類都差不多,我這個也是參考了別人的。另外優化了一下。並且添加了異常上傳至伺服器

相關推薦

全域性異常捕捉log伺服器

一個專案的完工後,我們也應給APP加上全域性的異常捕捉,並將異常log上傳到伺服器。有些朋友可能會遇到這樣的問題,異常是捕捉到了,但是還沒等到上傳到伺服器上APP就掛了。下面我們一起來看一下我在應用中的使用。 import java.io.File; import j

vue 電腦端調攝像頭拍照,canvas轉base64,base64轉圖片檔案伺服器

VUE(用了iview):  <template> <div id='cameraUpload'> <Form ref='member' :label-width='120' :model='member' :rules='memb

HTML5 檔案域+FileReader 分段讀取檔案伺服器(六)

說明:使用Ajax方式上傳,檔案不能過大,最好小於三四百兆,因為過多的連續Ajax請求會使後臺崩潰,獲取InputStream中資料會為空,尤其在Google瀏覽器測試過程中。 1.簡單分段讀取檔案為Blob,ajax上傳到伺服器 <div class="cont

HTML5 檔案域+FileReader 讀取檔案伺服器(三)

一、讀取檔案為blob並上傳到伺服器 HTML <div class="container"> <!--讀取要上傳的檔案--> <input type="file" id="file" /> <input type="bu

Intellij idea將jsp專案到處war包,伺服器

看這篇文章的前提是你已經會用IDEA寫專案。開啟專案,在右上角點配置。 選擇Artifacts,再點綠色加號。選擇第三個,再選擇Empty 然後在右側欄進行如下設定,最後點OK 然後再點這個綠色加號,選中你的jsp所在目錄並OK 以後在專案裡按ct

如何使用html5 canvas畫布對本地視訊進行截圖伺服器

前端程式碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">

Android調取系統相簿和相機照片設定到ImageView伺服器

網上的這類答案很多,不同的手機也會出現不同的情況,自己每次做這個功能都要掉進去很多次坑,分享給大家,也自己做一個筆記 話不多先看下效果 程式碼開始: 首先定義一個 PopupW

HTML5 本地裁剪圖片伺服器 canvas圖片 canvas圖片裁剪

很多情況下使用者上傳的圖片都需要經過裁剪,比如頭像啊什麼的。但以前實現這類需求都很複雜,往往需要先把圖片上傳到伺服器,然後返回給使用者,讓使用者確定裁剪座標,傳送給伺服器,伺服器裁剪完再返回給使用者,來回需要 5 步。步驟繁瑣不說,當很多使用者上傳圖片的時候也很影響伺服器

ionic3從手機相簿選擇多張照片預覽伺服器

安裝外掛①image-picker選擇多張照片--參照https://ionicframework.com/docs/native/image-picker/命令--ionic cordova plugin add cordova-plugin-telerik-imagepi

HTML5 本地裁剪圖片伺服器(老梗)

很多情況下使用者上傳的圖片都需要經過裁剪,比如頭像啊什麼的。但以前實現這類需求都很複雜,往往需要先把圖片上傳到伺服器,然後返回給使用者,讓使用者確定裁剪座標,傳送給伺服器,伺服器裁剪完再返回給使用者,來回需要 5 步。步驟繁瑣不說,當很多使用者上傳圖片的時候也很影響伺服器效

Unity3d 截圖伺服器

最近專案所需,需要捕抓影象並上傳到伺服器。 參考了別人的文章,加以改動。 寫此部落格以記錄。 參考部落格 設定全域性變數 public Camera cutFrameCamer; Rect canvas; 開始截圖 canvas.Set(0, 0, Screen.w

Android自定義全域性捕獲異常,實現實時收集APP崩潰crash資訊

一、異常收集 目的:在APP上線後,可能會出現一些BUG導致了APP的閃退,使用者體驗就非常致命,我們一定要第一時間找到問題的所在,去處理掉問題,處理有方法有兩種,一是發一個修改後的新版本,另一個是用熱修復釋出一個更新補丁,具體選擇哪一種符合自己需求就行。 我們主要說的異常

eclipse 整合maven、git。 eclipse 建立maven專案到騰訊git(或阿里雲git、gitlab、github、公司內部git伺服器等git倉庫)

我們先起git倉庫和專案起好名字 git倉庫名:TestGit 專案名:TestGit   1、下載安裝git: https://blog.csdn.net/xiaoshizi4/article/details/83478594 2、下載安裝maven:&nb

IntelliJ IDEA實現遠端連線linux,檔案到linux伺服器(SSH會話功能和SFTP功能)

注意: eclipse的SSH會話功能和SFTP功能這裡不會說 點選以下連結可檢視   eclipse的SSH會話功能和SFTP功能 而IntelliJ IDEA(以下簡稱為IDEA)這麼強大的開發工具自然也有該功能,這篇部落格就介紹一下IDEA的SSH會話功能

Mac連線Linux伺服器、解壓檔案

       由於工作原因,要求在Linux伺服器沒網路的情況下部署專案——首先我要做的是將相關檔案上傳至伺服器。我在網上搜了很多相關資料,結合自身實際情況,整理出我所做的步驟,以供參考。 目的:Mac連線上Linux伺服器,並將檔案上傳至Linux伺服器

根據base64轉換成圖片伺服器

package com.hzlq.appfactory.common.util; import it.sauronsoftware.base64.Base64; import java.io.ByteArrayInputStream; import jav

jenkins+svn完整打包到linux伺服器

因為公司用的是svn版本管理工具並且部署在了windows伺服器上,所以測試環使用jenkins需要部署兩套環境, 一套是在本地windows伺服器,jenkins從svn下載程式碼完成打包並上傳到linux跳板機上 一套是在linux環境上,把跳板機上的包上傳到對應伺服器上並備份以前版本,重啟新jar包

Java實現圖片伺服器的圖片讀取出來

題外話:推薦一個專注於Java開發的網站,做提升學習,價值閱讀: 同時,掃碼關注後端技術精選,回覆“學習資料”,領取100套小程式原始碼+小程式開發視訊和基本Java經典書籍電子版 在很多的網站都可以實現上傳頭像,可以選擇自己喜歡的圖片做頭像,從本地上傳,下次登入時可

多選本地相簿中的圖片展示(仿QQ空間動態傳送頁面)伺服器

最近公司專案需要從本地上傳圖片到伺服器,直接去找才發現安卓居然還有這麼坑的時候,呼叫原生的只能選擇一張圖片,而且還沒有任何的細節優化,觸控圖片就直接返回了。這肯定不行啊!於是就在網上找啊找。。。找啊找。。。有很多都寫得花裡胡哨的看不懂,而且介面的UI也是low的不行。。終於

linux自動備份oracle資料庫到備份伺服器 指令碼實現

實際專案中,備份資料是不可缺少的一步,完成資料的自動備份減少個人的工作量,是我們的目標。之前很少寫過指令碼,不過這些簡單的操作還是可以做到的!話不多說,開始具體介紹: oracle版本:10.2.0 作業系統:linuxredhat6.3 具體操作: (1)在伺服器上建立備