当前位置:   article > 正文

Android日志和崩溃信息记录 (Timber,logback,UncaughtExceptionHandler)_timber日志

timber日志

 

在程序开发过程中,需要记录程序运行中的运行日志。同时很多时候,程序运行中可能会遇到种种异常导致崩溃,在使用AndroidStudio调试过程中,可以在logcat中查看这些异常。但是apk安装在用户手机上,就需要程序自己将这些异常进行捕获并记录在日志中,供开发人员后续进行问题排查。

一、日志记录

1、Timber

一个简单的日志类,Timber把一种日志记录方法看做一颗树tree,Timber则是管理着一片森林,具体树怎么种(日志如何记录),使用哪棵树则由你决定。Timber默认自带的是DebugTree这个类。

step1:在build.gradle中引入

    implementation 'com.jakewharton.timber:timber:4.7.1'

GitHub:https://github.com/JakeWharton/timber 

step2:根据官方demo,应在application的onCreate中添加下述代码:

  1. @Override
  2. public void onCreate() {
  3. super.onCreate();
  4. if (BuildConfig.DEBUG) {
  5. Timber.plant(new DebugTree());
  6. } else {
  7. Timber.plant(new CrashReportingTree());
  8. }
  9. }

其中CrashReportingTree这个类,Timber并没有实现,这段代码只是告诉你,你可以自己定义一个tree来进行日志记录。

那么接下来我们自己来定义一棵树。在使用中,我需要将日志实时保存在文件中供后续使用,因此需要引入一个将日志记录在文件中的工具类logback-android。

2、logback-android

step1:在build.gradle中引入

  1. compile 'org.slf4j:slf4j-api:1.7.25'
  2. compile 'org.litepal.android:core:2.0.0'

GitHub:https://github.com/tony19/logback-android

step2:在assets里创建一个logback.xml文件,定义日志文件生成规则。

step3:配置logback.xml文件(将日志保存在手机外部存储中)

  1. <!--debug属性用来决定是否打印logback的日志信息-->
  2. <configuration debug='false'>
  3. <!--声明一个属性,用来指定log文件存放的路径 此处使用外部存储路径-->
  4. <property name="LOG_DIR" value="${EXT_DIR}/log"/>
  5. <!--声明一个时间戳-->
  6. <timestamp datePattern="yyyyMMdd" key="today"/>
  7. <!--用于在控制台输出的Appender-->
  8. <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
  9. <encoder>
  10. <pattern>%-5relative [%thread][%file:%M:%line] - %msg%n</pattern>
  11. </encoder>
  12. </appender>
  13. <!--声明一个FileAppender-->
  14. <appender name="BASE_FILE" class="ch.qos.logback.core.FileAppender">
  15. <!--初始化的时候不创建文件,在第一次使用的时候创建文件-->
  16. <lazy>true</lazy>
  17. <!--log追加到文件,否则覆盖文件-->
  18. <append>true</append>
  19. <!--用来保存log的文件全路径 /log/-->
  20. <file>${LOG_DIR}/base.log</file>
  21. <!--输出log的格式-->
  22. <encoder>
  23. <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n</pattern>
  24. </encoder>
  25. </appender>
  26. <!--声明一个RollingFileAppender-->
  27. <appender name="BASE_ROLL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  28. <file>${LOG_DIR}/base.roll.${today}.log</file>
  29. <append>true</append>
  30. <encoder>
  31. <pattern>%date %msg%n</pattern>
  32. </encoder>
  33. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  34. <fileNamePattern>${LOG_DIR}/base.roll.%d{yyyy-MM-dd}.log</fileNamePattern>
  35. <!--最大保存7天的日志-->
  36. <maxHistory>7</maxHistory>
  37. </rollingPolicy>
  38. <!--文件大于10mb,切换文件-->
  39. <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
  40. <maxFileSize>10MB</maxFileSize>
  41. </triggeringPolicy>
  42. </appender>
  43. <!--指定采用BASE_ROLL_FILE声明的RollingFileAppender输出日志-->
  44. <logger name="admin">
  45. <appender-ref ref="BASE_ROLL_FILE"/>
  46. </logger>
  47. </configuration>

 

3、使用logback来定义FileLoggingTree 

  1. import android.util.Log;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import timber.log.Timber;
  5. public class FileLoggingTree extends Timber.DebugTree{
  6. static Logger mLogger = LoggerFactory.getLogger(FileLoggingTree.class);
  7. @Override
  8. protected void log(int priority, String tag, String message, Throwable t) {
  9. if (priority == Log.VERBOSE) {
  10. return;
  11. }
  12. String logMessage = tag + ": " + message;
  13. switch (priority) {
  14. case Log.DEBUG:
  15. mLogger.debug(logMessage);
  16. break;
  17. case Log.INFO:
  18. mLogger.info(logMessage);
  19. break;
  20. case Log.WARN:
  21. mLogger.warn(logMessage);
  22. break;
  23. case Log.ERROR:
  24. mLogger.error(logMessage);
  25. break;
  26. }
  27. }
  28. }

 

 4、程序中的使用

step1:为了方便在程序中使用,将上述代码封装在MyLogger类中。

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import timber.log.Timber;
  4. public class MyLogger {
  5. private static Logger logger =null;
  6. //标识日志类是否进行初始化
  7. private static boolean isInit=false;
  8. //初始化timber,并声明使用FileLoggingTree
  9. public static void initLogger(){
  10. if (BuildConfig.DEBUG) {
  11. Timber.plant(new Timber.DebugTree());
  12. } else {
  13. Timber.plant(new FileLoggingTree());
  14. }
  15. isInit = true;
  16. }
  17. public static Logger getLogger(){
  18. if(!isInit){
  19. initLogger();
  20. }
  21. if(logger==null){
  22. //按照logback.xml文件中声明的方式进行日志存储
  23. logger = LoggerFactory.getLogger("admin");
  24. }
  25. return logger;
  26. }
  27. }

 step2:在程序任意地方,调用下述代码,完成日志记录。

  1. MyLogger.getLogger().trace("XXXXXX");
  2. MyLogger.getLogger().debug("XXXXXX");
  3. MyLogger.getLogger().info("XXXXXX");
  4. MyLogger.getLogger().error("XXXXXX");
  5. MyLogger.getLogger().warn("XXXXXX");

 

二、崩溃信息

Android 的Thread 类中提供了一个方法 setDefaultUncaughtExceptionHandler,可以捕获程序运行中的异常。当崩溃发生的时候,系统就会回调 UncaughtExceptionHandler 的 uncaughtException 方法,在 uncaughtException 方法中可以获取到异常信息,可以选择把异常信息存储到logback.xml中指定路径。

step1:我们需要继承Thread.UncaughtExceptionHandler 接口,重写其 uncaughtException 方法,在该方法中获取异常信息并将其保存在log文件中。

  1. import android.util.Log;
  2. import java.io.PrintWriter;
  3. import java.io.StringWriter;
  4. import java.io.Writer;
  5. public class CrashHandler implements Thread.UncaughtExceptionHandler {
  6. @Override
  7. public void uncaughtException(Thread thread, Throwable throwable) {
  8. //获取崩溃信息
  9. String stackTraceInfo = getStackTraceInfo(throwable);
  10. //将崩溃信息记录
  11. saveThrowableMessage(stackTraceInfo);
  12. }
  13. /**
  14. * 获取错误的信息
  15. */
  16. private String getStackTraceInfo(final Throwable throwable) {
  17. PrintWriter pw = null;
  18. Writer writer = new StringWriter();
  19. try {
  20. pw = new PrintWriter(writer);
  21. throwable.printStackTrace(pw);
  22. } catch (Exception e) {
  23. return "";
  24. } finally {
  25. if (pw != null) {
  26. pw.close();
  27. }
  28. }
  29. return writer.toString();
  30. }
  31. /**
  32. * 记录奔溃信息到log文件
  33. */
  34. private void saveThrowableMessage(String errorMessage) {
  35. MyLogger.getLogger().trace(errorMessage);
  36. }
  37. }

step2:然调用 Thread 的 setDefultUncaughtExceptionHandler 方法将它设置为线程默认的异常处理器。 

  1. public class MainActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. //初始化异常崩溃捕捉线程
  6. CrashHandler handler = new CrashHandler();
  7. Thread.setDefaultUncaughtExceptionHandler(handler);
  8. }
  9. }

-------------------------

CSDN源码下载:

https://download.csdn.net/download/elvia7/11119227

参考:

https://blog.csdn.net/Tomasyb/article/details/76034231

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/808162
推荐阅读
相关标签
  

闽ICP备14008679号