赞
踩
在程序开发过程中,需要记录程序运行中的运行日志。同时很多时候,程序运行中可能会遇到种种异常导致崩溃,在使用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
参考:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。