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

 

在程序开发过程中,需要记录程序运行中的运行日志。同时很多时候,程序运行中可能会遇到种种异常导致崩溃,在使用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中添加下述代码:

 @Override
    public void onCreate() {
        super.onCreate();

        if (BuildConfig.DEBUG) {
            Timber.plant(new DebugTree());
        } else {
            Timber.plant(new CrashReportingTree());
        }
    }
 

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

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

2、logback-android

step1:在build.gradle中引入

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

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

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

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

<!--debug属性用来决定是否打印logback的日志信息-->
<configuration debug='false'>

    <!--声明一个属性,用来指定log文件存放的路径 此处使用外部存储路径-->
    <property name="LOG_DIR" value="${EXT_DIR}/log"/>

    <!--声明一个时间戳-->
    <timestamp datePattern="yyyyMMdd" key="today"/>

    <!--用于在控制台输出的Appender-->
    <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
        <encoder>
            <pattern>%-5relative [%thread][%file:%M:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <!--声明一个FileAppender-->
    <appender name="BASE_FILE" class="ch.qos.logback.core.FileAppender">
        <!--初始化的时候不创建文件,在第一次使用的时候创建文件-->
        <lazy>true</lazy>
        <!--log追加到文件,否则覆盖文件-->
        <append>true</append>
        <!--用来保存log的文件全路径 /log/-->
        <file>${LOG_DIR}/base.log</file>
        <!--输出log的格式-->
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n</pattern> 
        </encoder>
    </appender>

    <!--声明一个RollingFileAppender-->
    <appender name="BASE_ROLL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/base.roll.${today}.log</file>
        <append>true</append>
        <encoder>
            <pattern>%date %msg%n</pattern>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_DIR}/base.roll.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--最大保存7天的日志-->
            <maxHistory>7</maxHistory>
        </rollingPolicy>

        <!--文件大于10mb,切换文件-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>10MB</maxFileSize>
        </triggeringPolicy>
    </appender>

    <!--指定采用BASE_ROLL_FILE声明的RollingFileAppender输出日志-->
    <logger name="admin">
        <appender-ref ref="BASE_ROLL_FILE"/>
    </logger> 
</configuration>

 

3、使用logback来定义FileLoggingTree 

import android.util.Log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import timber.log.Timber;

public class FileLoggingTree extends Timber.DebugTree{

    static Logger mLogger = LoggerFactory.getLogger(FileLoggingTree.class);

    @Override
    protected void log(int priority, String tag, String message, Throwable t) {
        if (priority == Log.VERBOSE) {
            return;
        }

        String logMessage = tag + ": " + message;
        switch (priority) {
            case Log.DEBUG:
                mLogger.debug(logMessage);
                break;
            case Log.INFO:
                mLogger.info(logMessage);
                break;
            case Log.WARN:
                mLogger.warn(logMessage);
                break;
            case Log.ERROR:
                mLogger.error(logMessage);
                break;
        }
    }
}

 

 4、程序中的使用

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import timber.log.Timber;

public class MyLogger {

    private static Logger logger =null;

    //标识日志类是否进行初始化
    private static boolean isInit=false;

    //初始化timber,并声明使用FileLoggingTree
    public static void initLogger(){

        if (BuildConfig.DEBUG) {
            Timber.plant(new Timber.DebugTree());
        } else {
            Timber.plant(new FileLoggingTree());
        }

        isInit = true;
    }

    public  static  Logger getLogger(){
        if(!isInit){
            initLogger();
        }
        if(logger==null){
            //按照logback.xml文件中声明的方式进行日志存储
            logger = LoggerFactory.getLogger("admin");
        }
        return logger;
    }

}

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

        MyLogger.getLogger().trace("XXXXXX");
        MyLogger.getLogger().debug("XXXXXX");
        MyLogger.getLogger().info("XXXXXX");
        MyLogger.getLogger().error("XXXXXX");
        MyLogger.getLogger().warn("XXXXXX");

 

二、崩溃信息

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

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


import android.util.Log;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;

public class CrashHandler implements Thread.UncaughtExceptionHandler {


    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
       //获取崩溃信息
        String stackTraceInfo = getStackTraceInfo(throwable);
       //将崩溃信息记录
        saveThrowableMessage(stackTraceInfo);

    }

    /**
     * 获取错误的信息
     */
    private String getStackTraceInfo(final Throwable throwable) {
        PrintWriter pw = null;
        Writer writer = new StringWriter();
        try {
            pw = new PrintWriter(writer);
            throwable.printStackTrace(pw);
        } catch (Exception e) {
            return "";
        } finally {
            if (pw != null) {
                pw.close();
            }
        }
        return writer.toString();
    }


    /**
     * 记录奔溃信息到log文件
     */

    private void saveThrowableMessage(String errorMessage) {
        MyLogger.getLogger().trace(errorMessage);
    }



}

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

public class MainActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      
        //初始化异常崩溃捕捉线程
        CrashHandler handler = new CrashHandler();
        Thread.setDefaultUncaughtExceptionHandler(handler);
        
    }
}

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

CSDN源码下载:

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

参考:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值