文章大纲

一、Android崩溃日志管理简介
二、崩溃日志管理实战
三、项目源码下载

 

一、Android崩溃日志管理简介

1. 什么是android崩溃日志管理

  开发中有些地方未注意可能造成异常抛出未能caught到,然后弹出系统对话框强制退出。这种交互不好,而且开发者也不能及时获取到底哪里出问题。因此我们可以使用android的UncaughtExceptionHandler来处理这种异常。

2. 操作逻辑

用户端(出现崩溃)
  我们会封装一个通用的jar包,该jar包包括日志打印、捕获异常信息逻辑、网络传输、设置Debug和Release模式、获取本机的相关信息等,当出现异常时,将异常信息以文件方式保存在用户手机中,并且发送到后台,当后台接收成功时,自动删除用户手机的崩溃信息文件,若接收失败,在下次发生崩溃时,将历史发送失败的崩溃一同发送。

接收端(后台)
  我们会编写一个地址,用于接收异常的具体信息,并储存在本地文件中,以此作为日志进行管理。

二、崩溃日志管理实战

1. 后台端

  在该实战中,我以简单的servlet进行讲解,实际项目中,可以以ssm或spring boot等框架进行操作。

  1. /**
  2. * 接收崩溃信息,并进行打印(实际项目中,需要以文件形式归档)
  3. * @author wxc
  4. *
  5. */
  6. public class Test extends HttpServlet {
  7. public void doGet(HttpServletRequest request, HttpServletResponse response)
  8. throws ServletException, IOException {
  9. doPost(request, response);
  10. }
  11. public void doPost(HttpServletRequest request, HttpServletResponse response)
  12. throws ServletException, IOException {
  13. //获取客户端传送过来的信息流
  14. BufferedReader in=new BufferedReader(new InputStreamReader(request.getInputStream()));
  15. StringBuilder sb = new StringBuilder();
  16. String line = null;
  17. while ((line = in.readLine()) != null) {
  18. //将信息流进行打印
  19. System.out.println(line);
  20. }
  21. }
  22. }

2. 客户端通用项目

网络请求相关的配置管理类:HttpManager.java

  1. /**
  2. *
  3. * 网络请求相关的配置管理
  4. *
  5. * @author 吴晓畅
  6. *
  7. */
  8. public class HttpManager {
  9. private static final int SET_CONNECTION_TIMEOUT = 5 * 1000;
  10. private static final int SET_SOCKET_TIMEOUT = 20 * 1000;
  11. private static final String BOUNDARY = getBoundry();// UUID.randomUUID().toString();
  12. private static final String MP_BOUNDARY = "--" + BOUNDARY;
  13. private static final String END_MP_BOUNDARY = "--" + BOUNDARY + "--";
  14. private static final String LINEND = "\r\n";
  15. private static final String CHARSET = "UTF-8";
  16. public static String uploadFile(String url, HttpParameters params,
  17. File logFile) throws IOException{
  18. HttpClient client = getHttpClient();
  19. HttpPost post = new HttpPost(url);
  20. ByteArrayOutputStream bos = null;
  21. FileInputStream logFileInputStream = null;
  22. String result = null;
  23. try {
  24. bos = new ByteArrayOutputStream();
  25. if(params != null){
  26. String key = "";
  27. for (int i = 0; i < params.size(); i++) {
  28. key = params.getKey(i);
  29. StringBuilder temp = new StringBuilder(10);
  30. temp.setLength(0);
  31. temp.append(MP_BOUNDARY).append(LINEND);
  32. temp.append("content-disposition: form-data; name=\"").append(key)
  33. .append("\"").append(LINEND + LINEND);
  34. temp.append(params.getValue(key)).append(LINEND);
  35. bos.write(temp.toString().getBytes());
  36. }
  37. }
  38. StringBuilder temp = new StringBuilder();
  39. temp.append(MP_BOUNDARY).append(LINEND);
  40. temp.append(
  41. "content-disposition: form-data; name=\"logfile\"; filename=\"")
  42. .append(logFile.getName()).append("\"").append(LINEND);
  43. temp.append("Content-Type: application/octet-stream; charset=utf-8").append(LINEND + LINEND);
  44. bos.write(temp.toString().getBytes());
  45. logFileInputStream = new FileInputStream(logFile);
  46. byte[] buffer = new byte[1024*8];//8k
  47. while(true){
  48. int count = logFileInputStream.read(buffer);
  49. if(count == -1){
  50. break;
  51. }
  52. bos.write(buffer, 0, count);
  53. }
  54. bos.write((LINEND+LINEND).getBytes());
  55. bos.write((END_MP_BOUNDARY+LINEND).getBytes());
  56. ByteArrayEntity formEntity = new ByteArrayEntity(bos.toByteArray());
  57. post.setEntity(formEntity);
  58. HttpResponse response = client.execute(post);
  59. StatusLine status = response.getStatusLine();
  60. int statusCode = status.getStatusCode();
  61. Log.i("HttpManager", "返回结果为"+statusCode);
  62. if(statusCode == HttpStatus.SC_OK){
  63. result = readHttpResponse(response);
  64. }
  65. } catch (IOException e) {
  66. throw e;
  67. }finally{
  68. if(bos != null){
  69. try {
  70. bos.close();
  71. } catch (IOException e) {
  72. throw e;
  73. }
  74. }
  75. if(logFileInputStream != null){
  76. try {
  77. logFileInputStream.close();
  78. } catch (IOException e) {
  79. throw e;
  80. }
  81. }
  82. }
  83. return result;
  84. }
  85. private static String readHttpResponse(HttpResponse response){
  86. String result = null;
  87. HttpEntity entity = response.getEntity();
  88. InputStream inputStream;
  89. try {
  90. inputStream = entity.getContent();
  91. ByteArrayOutputStream content = new ByteArrayOutputStream();
  92. int readBytes = 0;
  93. byte[] sBuffer = new byte[512];
  94. while ((readBytes = inputStream.read(sBuffer)) != -1) {
  95. content.write(sBuffer, 0, readBytes);
  96. }
  97. result = new String(content.toByteArray(), CHARSET);
  98. return result;
  99. } catch (IllegalStateException e) {
  100. // TODO Auto-generated catch block
  101. e.printStackTrace();
  102. } catch (IOException e) {
  103. // TODO Auto-generated catch block
  104. e.printStackTrace();
  105. }
  106. return result;
  107. }
  108. private static HttpClient getHttpClient() {
  109. try {
  110. KeyStore trustStore = KeyStore.getInstance(KeyStore
  111. .getDefaultType());
  112. trustStore.load(null, null);
  113. SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
  114. sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
  115. HttpParams params = new BasicHttpParams();
  116. HttpConnectionParams.setConnectionTimeout(params, 10000);
  117. HttpConnectionParams.setSoTimeout(params, 10000);
  118. HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
  119. HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
  120. SchemeRegistry registry = new SchemeRegistry();
  121. registry.register(new Scheme("http", PlainSocketFactory
  122. .getSocketFactory(), 80));
  123. registry.register(new Scheme("https", sf, 443));
  124. ClientConnectionManager ccm = new ThreadSafeClientConnManager(
  125. params, registry);
  126. HttpConnectionParams.setConnectionTimeout(params,
  127. SET_CONNECTION_TIMEOUT);
  128. HttpConnectionParams.setSoTimeout(params, SET_SOCKET_TIMEOUT);
  129. HttpClient client = new DefaultHttpClient(ccm, params);
  130. return client;
  131. } catch (Exception e) {
  132. // e.printStackTrace();
  133. return new DefaultHttpClient();
  134. }
  135. }
  136. private static class MySSLSocketFactory extends SSLSocketFactory {
  137. SSLContext sslContext = SSLContext.getInstance("TLS");
  138. public MySSLSocketFactory(KeyStore truststore)
  139. throws NoSuchAlgorithmException, KeyManagementException,
  140. KeyStoreException, UnrecoverableKeyException {
  141. super(truststore);
  142. TrustManager tm = new X509TrustManager() {
  143. @Override
  144. public X509Certificate[] getAcceptedIssuers() {
  145. // TODO Auto-generated method stub
  146. return null;
  147. }
  148. @Override
  149. public void checkServerTrusted(X509Certificate[] chain,
  150. String authType) throws CertificateException {
  151. // TODO Auto-generated method stub
  152. }
  153. @Override
  154. public void checkClientTrusted(X509Certificate[] chain,
  155. String authType) throws CertificateException {
  156. // TODO Auto-generated method stub
  157. }
  158. };
  159. sslContext.init(null, new TrustManager[] { tm }, null);
  160. }
  161. @Override
  162. public Socket createSocket() throws IOException {
  163. return sslContext.getSocketFactory().createSocket();
  164. }
  165. @Override
  166. public Socket createSocket(Socket socket, String host, int port,
  167. boolean autoClose) throws IOException, UnknownHostException {
  168. return sslContext.getSocketFactory().createSocket(socket, host,
  169. port, autoClose);
  170. }
  171. }
  172. private static String getBoundry() {
  173. StringBuffer _sb = new StringBuffer();
  174. for (int t = 1; t < 12; t++) {
  175. long time = System.currentTimeMillis() + t;
  176. if (time % 3 == 0) {
  177. _sb.append((char) time % 9);
  178. } else if (time % 3 == 1) {
  179. _sb.append((char) (65 + time % 26));
  180. } else {
  181. _sb.append((char) (97 + time % 26));
  182. }
  183. }
  184. return _sb.toString();
  185. }
  186. }

文件上传相关类:UploadLogManager.java

  1. package com.qihoo.linker.logcollector.upload;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.util.logging.Logger;
  5. import com.qihoo.linker.logcollector.capture.LogFileStorage;
  6. import android.content.Context;
  7. import android.os.Handler;
  8. import android.os.HandlerThread;
  9. import android.os.Looper;
  10. import android.os.Message;
  11. import android.util.Log;
  12. /**
  13. *
  14. * @author 吴晓畅
  15. *
  16. */
  17. public class UploadLogManager {
  18. private static final String TAG = UploadLogManager.class.getName();
  19. private static UploadLogManager sInstance;
  20. private Context mContext;
  21. private HandlerThread mHandlerThread;
  22. private static volatile MyHandler mHandler;
  23. private volatile Looper mLooper;
  24. private volatile boolean isRunning = false;
  25. private String url;
  26. private HttpParameters params;
  27. private UploadLogManager(Context c){
  28. mContext = c.getApplicationContext();
  29. mHandlerThread = new HandlerThread(TAG + ":HandlerThread");
  30. mHandlerThread.start();
  31. }
  32. //初始化UploadLogManager类
  33. public static synchronized UploadLogManager getInstance(Context c){
  34. if(sInstance == null){
  35. sInstance = new UploadLogManager(c);
  36. }
  37. return sInstance;
  38. }
  39. /**
  40. * 执行文件上传具体操作
  41. *
  42. * @param url
  43. * @param params
  44. */
  45. public void uploadLogFile(String url , HttpParameters params){
  46. this.url = url;
  47. this.params = params;
  48. mLooper = mHandlerThread.getLooper();
  49. mHandler = new MyHandler(mLooper);
  50. if(mHandlerThread == null){
  51. return;
  52. }
  53. if(isRunning){
  54. return;
  55. }
  56. mHandler.sendMessage(mHandler.obtainMessage());
  57. isRunning = true;
  58. }
  59. //用于uploadLogFile方法调用的线程
  60. private final class MyHandler extends Handler{
  61. public MyHandler(Looper looper) {
  62. super(looper);
  63. // TODO Auto-generated constructor stub
  64. }
  65. @Override
  66. public void handleMessage(Message msg) {
  67. File logFile = LogFileStorage.getInstance(mContext).getUploadLogFile();
  68. if(logFile == null){
  69. isRunning = false;
  70. return;
  71. }
  72. try {
  73. String result = HttpManager.uploadFile(url, params, logFile);
  74. Log.i("UpLoad", "服务端返回数据为"+result);
  75. if(result != null){
  76. Boolean isSuccess = LogFileStorage.getInstance(mContext).deleteUploadLogFile();
  77. Log.i("UpLoad", "删除文件结果为"+isSuccess);
  78. }
  79. } catch (IOException e) {
  80. // TODO Auto-generated catch block
  81. e.printStackTrace();
  82. }finally{
  83. isRunning = false;
  84. }
  85. }
  86. }
  87. }

客户端崩溃日志文件的删除,保存等操作类:LogFileStorage.java
文件保存在Android/data/包名/Log/下

  1. package com.qihoo.linker.logcollector.capture;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import com.qihoo.linker.logcollector.utils.LogCollectorUtility;
  5. import com.qihoo.linker.logcollector.utils.LogHelper;
  6. import android.content.Context;
  7. import android.util.Log;
  8. /**
  9. *
  10. * 客户端崩溃日志文件的删除,保存等操作
  11. *
  12. * @author 吴晓畅
  13. *
  14. */
  15. public class LogFileStorage {
  16. private static final String TAG = LogFileStorage.class.getName();
  17. public static final String LOG_SUFFIX = ".log";
  18. private static final String CHARSET = "UTF-8";
  19. private static LogFileStorage sInstance;
  20. private Context mContext;
  21. private LogFileStorage(Context ctx) {
  22. mContext = ctx.getApplicationContext();
  23. }
  24. public static synchronized LogFileStorage getInstance(Context ctx) {
  25. if (ctx == null) {
  26. LogHelper.e(TAG, "Context is null");
  27. return null;
  28. }
  29. if (sInstance == null) {
  30. sInstance = new LogFileStorage(ctx);
  31. }
  32. return sInstance;
  33. }
  34. public File getUploadLogFile(){
  35. File dir = mContext.getFilesDir();
  36. File logFile = new File(dir, LogCollectorUtility.getMid(mContext)
  37. + LOG_SUFFIX);
  38. if(logFile.exists()){
  39. return logFile;
  40. }else{
  41. return null;
  42. }
  43. }
  44. //删除客户端中崩溃日志文件
  45. public boolean deleteUploadLogFile(){
  46. File dir = mContext.getFilesDir();
  47. File logFile = new File(dir, LogCollectorUtility.getMid(mContext)
  48. + LOG_SUFFIX);
  49. Log.i("Log",
  50. LogCollectorUtility.getMid(mContext)
  51. + LOG_SUFFIX);
  52. return logFile.delete();
  53. }
  54. //保存文件
  55. public boolean saveLogFile2Internal(String logString) {
  56. try {
  57. File dir = mContext.getFilesDir();
  58. if (!dir.exists()) {
  59. dir.mkdirs();
  60. }
  61. File logFile = new File(dir, LogCollectorUtility.getMid(mContext)
  62. + LOG_SUFFIX);
  63. FileOutputStream fos = new FileOutputStream(logFile , true);
  64. fos.write(logString.getBytes(CHARSET));
  65. fos.close();
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. LogHelper.e(TAG, "saveLogFile2Internal failed!");
  69. return false;
  70. }
  71. return true;
  72. }
  73. public boolean saveLogFile2SDcard(String logString, boolean isAppend) {
  74. if (!LogCollectorUtility.isSDcardExsit()) {
  75. LogHelper.e(TAG, "sdcard not exist");
  76. return false;
  77. }
  78. try {
  79. File logDir = getExternalLogDir();
  80. if (!logDir.exists()) {
  81. logDir.mkdirs();
  82. }
  83. File logFile = new File(logDir, LogCollectorUtility.getMid(mContext)
  84. + LOG_SUFFIX);
  85. /*if (!isAppend) {
  86. if (logFile.exists() && !logFile.isFile())
  87. logFile.delete();
  88. }*/
  89. LogHelper.d(TAG, logFile.getPath());
  90. FileOutputStream fos = new FileOutputStream(logFile , isAppend);
  91. fos.write(logString.getBytes(CHARSET));
  92. fos.close();
  93. } catch (Exception e) {
  94. e.printStackTrace();
  95. Log.e(TAG, "saveLogFile2SDcard failed!");
  96. return false;
  97. }
  98. return true;
  99. }
  100. private File getExternalLogDir() {
  101. File logDir = LogCollectorUtility.getExternalDir(mContext, "Log");
  102. LogHelper.d(TAG, logDir.getPath());
  103. return logDir;
  104. }
  105. }

UncaughtExceptionHandler实现类:CrashHandler.java
  当出现异常时,会进入public void uncaughtException(Thread thread, Throwable ex) 方法中。

  1. /**
  2. *
  3. * 如果需要捕获系统的未捕获异常(如系统抛出了未知错误,这种异常没有捕获,这将导致系统莫名奇妙的关闭,使得用户体验差),
  4. * 可以通过UncaughtExceptionHandler来处理这种异常。
  5. *
  6. * @author 吴晓畅
  7. *
  8. */
  9. public class CrashHandler implements UncaughtExceptionHandler {
  10. private static final String TAG = CrashHandler.class.getName();
  11. private static final String CHARSET = "UTF-8";
  12. private static CrashHandler sInstance;
  13. private Context mContext;
  14. private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
  15. String appVerName;
  16. String appVerCode;
  17. String OsVer;
  18. String vendor;
  19. String model;
  20. String mid;
  21. //初始化该类
  22. private CrashHandler(Context c) {
  23. mContext = c.getApplicationContext();
  24. // mContext = c;
  25. appVerName = "appVerName:" + LogCollectorUtility.getVerName(mContext);
  26. appVerCode = "appVerCode:" + LogCollectorUtility.getVerCode(mContext);
  27. OsVer = "OsVer:" + Build.VERSION.RELEASE;
  28. vendor = "vendor:" + Build.MANUFACTURER;
  29. model = "model:" + Build.MODEL;
  30. mid = "mid:" + LogCollectorUtility.getMid(mContext);
  31. }
  32. //初始化该类
  33. public static CrashHandler getInstance(Context c) {
  34. if (c == null) {
  35. LogHelper.e(TAG, "Context is null");
  36. return null;
  37. }
  38. if (sInstance == null) {
  39. sInstance = new CrashHandler(c);
  40. }
  41. return sInstance;
  42. }
  43. public void init() {
  44. if (mContext == null) {
  45. return;
  46. }
  47. boolean b = LogCollectorUtility.hasPermission(mContext);
  48. if (!b) {
  49. return;
  50. }
  51. mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
  52. Thread.setDefaultUncaughtExceptionHandler(this);
  53. }
  54. /**
  55. * 发生异常时候进来这里
  56. */
  57. @Override
  58. public void uncaughtException(Thread thread, Throwable ex) {
  59. //
  60. handleException(ex);
  61. //
  62. ex.printStackTrace();
  63. if (mDefaultCrashHandler != null) {
  64. mDefaultCrashHandler.uncaughtException(thread, ex);
  65. } else {
  66. Process.killProcess(Process.myPid());
  67. // System.exit(1);
  68. }
  69. }
  70. //将异常信息保存成文件
  71. private void handleException(Throwable ex) {
  72. String s = fomatCrashInfo(ex);
  73. // String bes = fomatCrashInfoEncode(ex);
  74. LogHelper.d(TAG, s);
  75. // LogHelper.d(TAG, bes);
  76. //LogFileStorage.getInstance(mContext).saveLogFile2Internal(bes);
  77. LogFileStorage.getInstance(mContext).saveLogFile2Internal(s);
  78. if(Constants.DEBUG){
  79. LogFileStorage.getInstance(mContext).saveLogFile2SDcard(s, true);
  80. }
  81. }
  82. private String fomatCrashInfo(Throwable ex) {
  83. /*
  84. * String lineSeparator = System.getProperty("line.separator");
  85. * if(TextUtils.isEmpty(lineSeparator)){ lineSeparator = "\n"; }
  86. */
  87. String lineSeparator = "\r\n";
  88. StringBuilder sb = new StringBuilder();
  89. String logTime = "logTime:" + LogCollectorUtility.getCurrentTime();
  90. String exception = "exception:" + ex.toString();
  91. Writer info = new StringWriter();
  92. PrintWriter printWriter = new PrintWriter(info);
  93. ex.printStackTrace(printWriter);
  94. String dump = info.toString();
  95. String crashMD5 = "crashMD5:"
  96. + LogCollectorUtility.getMD5Str(dump);
  97. String crashDump = "crashDump:" + "{" + dump + "}";
  98. printWriter.close();
  99. sb.append("&start---").append(lineSeparator);
  100. sb.append(logTime).append(lineSeparator);
  101. sb.append(appVerName).append(lineSeparator);
  102. sb.append(appVerCode).append(lineSeparator);
  103. sb.append(OsVer).append(lineSeparator);
  104. sb.append(vendor).append(lineSeparator);
  105. sb.append(model).append(lineSeparator);
  106. sb.append(mid).append(lineSeparator);
  107. sb.append(exception).append(lineSeparator);
  108. sb.append(crashMD5).append(lineSeparator);
  109. sb.append(crashDump).append(lineSeparator);
  110. sb.append("&end---").append(lineSeparator).append(lineSeparator)
  111. .append(lineSeparator);
  112. return sb.toString();
  113. }
  114. private String fomatCrashInfoEncode(Throwable ex) {
  115. /*
  116. * String lineSeparator = System.getProperty("line.separator");
  117. * if(TextUtils.isEmpty(lineSeparator)){ lineSeparator = "\n"; }
  118. */
  119. String lineSeparator = "\r\n";
  120. StringBuilder sb = new StringBuilder();
  121. String logTime = "logTime:" + LogCollectorUtility.getCurrentTime();
  122. String exception = "exception:" + ex.toString();
  123. Writer info = new StringWriter();
  124. PrintWriter printWriter = new PrintWriter(info);
  125. ex.printStackTrace(printWriter);
  126. String dump = info.toString();
  127. String crashMD5 = "crashMD5:"
  128. + LogCollectorUtility.getMD5Str(dump);
  129. try {
  130. dump = URLEncoder.encode(dump, CHARSET);
  131. } catch (UnsupportedEncodingException e) {
  132. // TODO Auto-generated catch block
  133. e.printStackTrace();
  134. }
  135. String crashDump = "crashDump:" + "{" + dump + "}";
  136. printWriter.close();
  137. sb.append("&start---").append(lineSeparator);
  138. sb.append(logTime).append(lineSeparator);
  139. sb.append(appVerName).append(lineSeparator);
  140. sb.append(appVerCode).append(lineSeparator);
  141. sb.append(OsVer).append(lineSeparator);
  142. sb.append(vendor).append(lineSeparator);
  143. sb.append(model).append(lineSeparator);
  144. sb.append(mid).append(lineSeparator);
  145. sb.append(exception).append(lineSeparator);
  146. sb.append(crashMD5).append(lineSeparator);
  147. sb.append(crashDump).append(lineSeparator);
  148. sb.append("&end---").append(lineSeparator).append(lineSeparator)
  149. .append(lineSeparator);
  150. String bes = Base64.encodeToString(sb.toString().getBytes(),
  151. Base64.NO_WRAP);
  152. return bes;
  153. }
  154. }

项目调用封装类:LogCollector.java

  1. /**
  2. *
  3. * 执行文件上传相关的类
  4. *
  5. *
  6. * @author 吴晓畅
  7. *
  8. */
  9. public class LogCollector {
  10. private static final String TAG = LogCollector.class.getName();
  11. private static String Upload_Url;
  12. private static Context mContext;
  13. private static boolean isInit = false;
  14. private static HttpParameters mParams;
  15. //初始化文件上传的url,数据等内容
  16. public static void init(Context c , String upload_url , HttpParameters params){
  17. if(c == null){
  18. return;
  19. }
  20. if(isInit){
  21. return;
  22. }
  23. Upload_Url = upload_url;
  24. mContext = c;
  25. mParams = params;
  26. //初始化自己定义的异常处理
  27. CrashHandler crashHandler = CrashHandler.getInstance(c);
  28. crashHandler.init();
  29. isInit = true;
  30. }
  31. /**
  32. * 执行文件上传的网路请求
  33. *
  34. * if(isWifiOnly && !isWifiMode){
  35. return;
  36. }表示只在wifi状态下执行文件上传
  37. *
  38. * @param isWifiOnly
  39. */
  40. public static void upload(boolean isWifiOnly){
  41. if(mContext == null || Upload_Url == null){
  42. Log.d(TAG, "please check if init() or not");
  43. return;
  44. }
  45. if(!LogCollectorUtility.isNetworkConnected(mContext)){
  46. return;
  47. }
  48. boolean isWifiMode = LogCollectorUtility.isWifiConnected(mContext);
  49. if(isWifiOnly && !isWifiMode){
  50. return;
  51. }
  52. UploadLogManager.getInstance(mContext).uploadLogFile(Upload_Url, mParams);
  53. }
  54. /**
  55. * 用于设置是否为测试状态
  56. *
  57. * @param isDebug true为是,false为否 如果是,能看到LOG日志,同时能够在将文件夹看到崩溃日志
  58. */
  59. public static void setDebugMode(boolean isDebug){
  60. Constants.DEBUG = isDebug;
  61. LogHelper.enableDefaultLog = isDebug;
  62. }
  63. }

3. 客户端接入使用

为通用项目设置is Library模式

 
 

实际android项目使用

添加Library

 
 

在Application子类中进行初始化


  1. public class MyApplication extends Application {
  2. //后台地址地址
  3. private static final String UPLOAD_URL = "http://192.168.3.153:8080/bengkuitest/servlet/Test";
  4. @Override
  5. public void onCreate() {
  6. super.onCreate();
  7. boolean isDebug = true;
  8. //设置是否为测试模式,如果是,同时能够在将文件夹看到崩溃日志
  9. LogCollector.setDebugMode(isDebug);
  10. //params的数据可以为空 初始化LogCollector的相关数据,用于文件上传到服务器
  11. LogCollector.init(getApplicationContext(), UPLOAD_URL, null);
  12. }
  13. }

编写异常并上传异常

  1. public class MainActivity extends Activity implements OnClickListener {
  2. private Button btn_crash;
  3. private Button btn_upload;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. btn_crash = (Button) findViewById(R.id.button1);
  9. btn_upload = (Button) findViewById(R.id.button2);
  10. btn_crash.setOnClickListener(this);
  11. btn_upload.setOnClickListener(this);
  12. }
  13. //产生异常
  14. private void causeCrash(){
  15. String s = null;
  16. s.split("1");
  17. }
  18. //上传文件
  19. private void uploadLogFile(){
  20. //设置为只在wifi下上传文件
  21. boolean isWifiOnly = true;//only wifi mode can upload
  22. //执行文件上传服务器
  23. LogCollector.upload(isWifiOnly);//upload at the right time
  24. }
  25. @Override
  26. public void onClick(View v) {
  27. switch (v.getId()) {
  28. case R.id.button1:
  29. causeCrash();
  30. break;
  31. case R.id.button2:
  32. //上传文件
  33. uploadLogFile();
  34. break;
  35. default:
  36. break;
  37. }
  38. }
  39. }

运行结果如下图所示


  1. --No1Qr4Tu7Wx
  2. content-disposition: form-data; name="logfile"; filename="c5c63fec3651fdebdd411582793fa40c.log"
  3. Content-Type: application/octet-stream; charset=utf-8
  4. &start---
  5. logTime:2019-04-07 10:54:47
  6. appVerName:1.0
  7. appVerCode:1
  8. OsVer:5.1.1
  9. vendor:samsung
  10. model:SM-G955F
  11. mid:c5c63fec3651fdebdd411582793fa40c
  12. exception:java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String[] java.lang.String.split(java.lang.String)' on a null object reference
  13. crashMD5:74861b8fb97ef57b82a87a826ab6b08f
  14. crashDump:{java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String[] java.lang.String.split(java.lang.String)' on a null object reference
  15. at com.jiabin.logcollectorexample.MainActivity.causeCrash(MainActivity.java:32)
  16. at com.jiabin.logcollectorexample.MainActivity.onClick(MainActivity.java:45)
  17. at android.view.View.performClick(View.java:4780)
  18. at android.view.View$PerformClick.run(View.java:19866)
  19. at android.os.Handler.handleCallback(Handler.java:739)
  20. at android.os.Handler.dispatchMessage(Handler.java:95)
  21. at android.os.Looper.loop(Looper.java:135)
  22. at android.app.ActivityThread.main(ActivityThread.java:5293)
  23. at java.lang.reflect.Method.invoke(Native Method)
  24. at java.lang.reflect.Method.invoke(Method.java:372)
  25. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
  26. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
  27. }
  28. &end---
  29. --No1Qr4Tu7Wx--

三、项目源码下载

链接:https://pan.baidu.com/s/1kEGfJ3PSoDnsyulCAoimjg
密码:xy0l

 

Android之崩溃日志管理的更多相关文章

  1. 捕android程序崩溃日志

    主要类别: package com.example.callstatus; import java.io.File; import java.io.FileOutputStream; import j ...

  2. android app崩溃日志收集以及上传

    源代码获取请到github:https://github.com/DrJia/AndroidLogCollector 已经做成sdk的形式,源代码已公开,源代码看不懂的请自行google. 假设想定制 ...

  3. Android 简易崩溃日志保存

    仅仅做了简单的保存到了本地而已: 根据需要可以继续增加功能: 下一次启动上传到服务器: 增加应用版本,机型系统版本信息等: public class CrashSaver { public stati ...

  4. 保存android程序崩溃日志到SD卡

    private boolean writeToSDCard(Throwable ex) { boolean isDealing = false; if (Environment.getExternal ...

  5. iOS崩溃日志记录工具--CrashlyTics

    http://try.crashlytics.com Crashlytics优势: 1.Crashlytics基本不会漏掉任何应用崩溃的信息 2.Crashlytics对崩溃日志管理很人性化,会根据崩 ...

  6. 【Android应用开发】 Android 崩溃日志 本地存储 与 远程保存

    示例代码下载 : http://download.csdn.net/detail/han1202012/8638801; 一. 崩溃日志本地存储 1. 保存原理解析 崩溃信息本地保存步骤 : -- 1 ...

  7. android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地

    http://blog.csdn.net/jason0539/article/details/45602655 应用发生crash之后要查看log,判断问题出在什么地方,可是一旦应用发布出去,就要想办 ...

  8. android的Log日志打印管理工具类(一)

    android的Log日志的打印管理工具类: package com.gzcivil.utils; import android.util.Log; /** * 日志打印管理 * * @author ...

  9. android 程序崩溃crash日志的捕捉

    android 程序崩溃crash日志的捕捉 之前在项目开发过程中,一直会遇到程序崩溃了,但是测试組的哥哥们又没及时的导出日志.... 后来在诳群的时候听别人说起,腾讯有那么一个叫bugly的东西 将 ...

随机推荐

  1. Eclipse从数据库逆向生成Hibernate实体类和映射文件(Eclipse插件系列之HibernateTools)

    ♣下载安装Eclipse插件(HibernateTools) ♣Eclipse连接数据库(Mysql5.7) ♣新建hibernate.properties和hibernate.cfg.xml文件 ♣ ...

  2. border-radius 详解及示例

    border-radius [ˈbɔrdə(r)] - [ˈrediəs]   英文示意: border:边界,国界,边疆 radius:半径,范围   定义: 复合写法: border-radius ...

  3. 26.app后端怎么架设推送服务

    推送服务已经是app的标配了.架设推送服务,除了可以使用第三方服务商外,也有大量的开源技术可以选择. 现在推送主要分两块,android推送和ios推送,在下面分别论述: 1.    Android推 ...

  4. 玩转Spring MVC(二)----MVC框架

    早期程序员在编写代码时是没有一个规范的,系统的业务逻辑和数据库的访问时混合在一起的,不仅增加了大量的重复工作,而且增加了后期维护的难度. 后来,人们逐渐发现某些通用的功能是可以单独的封装起来的,这样就 ...

  5. VMware12下CentOS 7安装教程

    CentOS 7 DVD安装光盘(百度搜索CentOS即可找到官方主页):VMware Workstation 12 Pro及以上软件: 启动VMware Workstation 12 Pro程序,在 ...

  6. Linux下*.tar.gz/.tar.bz2 文件解压缩安装命令

    1. .tar.gz压缩命令: 命令格式: tar -zcvf 压缩文件名.tar.gz 被压缩文件名 可先切换到当前目录下.压缩文件名和被压缩文件名都可加入路径. 2. .tar.gz解压缩命令: ...

  7. nsqlookup_protocol_v1.go

    , atomic.LoadInt64(&client.peerInfo.lastUpdate))         now := time.Now()         p.ctx.nsqlook ...

  8. txn.go

    package clientv3 import (     "sync"     pb "github.com/coreos/etcd/etcdserver/etcdse ...

  9. BZOJ_1100_[POI2007]对称轴osi_KMP+计算几何

    BZOJ_1100_[POI2007]对称轴osi_KMP+计算几何 Description FGD小朋友——一个闻名遐迩的年轻数学家——有一个小MM,yours.FGD小朋友非常喜欢他的MM,所以他 ...

  10. QTTabBar

    出处:https://www.mokeyjay.com/archives/1811