Android_日志_开源日志库Logger的使用,日志重复打印、无法对齐问题。

文章基于 com.orhanobut:logger:2.2.0

Logger的GitHub地址:https://github.com/orhanobut/logger

1.添加依赖

implementation 'com.orhanobut:logger:2.2.0'

2.初始化

Logger.addLogAdapter(new AndroidLogAdapter());

或者

FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
        .showThreadInfo(true)   // (可选) 是否显示线程信息。Default:true
        .methodCount(1)        // (可选) 显示的方法数量。Default:2
        .methodOffset(0)       // (可选) 隐藏的方法数量,若设为 1,则隐藏跳转到日志输出的方法。Default:0
//        .logStrategy(customLog)   // (可选) 更改日志策略以打印输出。Default:new LogcatLogStrategy()。AS3.0会出现日志无法对齐的问题,解决方法见下文。
//        .tag("My custom tag")    // (可选) 每个日志的全局标记. Default:PRETTY_LOGGER
        .build();
  Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy){
  // 日志适配器通过检查此函数来检查日志是否应该打印。如果要禁用/隐藏输出日志,请重写isLoggable方法。true将打印日志消息,false会忽略它。
    @Override public boolean isLoggable(int priority, String tag) {
        return BuildConfig.DEBUG;
    }
});

注意:应放到application中初始化。为了避免出现日志打印重复的现象,需保证仅初始化一次LogAdapter。分析源码得:

LogAdapter以集合的形式存在,每次初始化都会向集合中添加LogAdapter

public final class Logger {
    public static void addLogAdapter(@NonNull LogAdapter adapter) {
        printer.addAdapter(checkNotNull(adapter));
    }
}

public interface Printer {
    void addAdapter(@NonNull LogAdapter adapter);
}

class LoggerPrinter implements Printer {
    private final List<LogAdapter> logAdapters = new ArrayList<>();
    @Override public void addAdapter(@NonNull LogAdapter adapter) {
        logAdapters.add(checkNotNull(adapter));
    }
}

日志输出会遍历LogAdapter集合,所以集合中有多少个LogAdapter就会输出多少次。

class LoggerPrinter implements Printer {
    @Override public synchronized void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable throwable) {
        if (throwable != null && message != null) {
            message += " : " + Utils.getStackTraceString(throwable);
        }
        if (throwable != null && message == null) {
            message = Utils.getStackTraceString(throwable);
        }
        if (Utils.isEmpty(message)) {
            message = "Empty/NULL log message";
        }

        for (LogAdapter adapter : logAdapters) {
            if (adapter.isLoggable(priority, tag)) {
                adapter.log(priority, tag, message);
            }
        }
    }
}

3.使用

Logger.d("debug");
Logger.e("error");
Logger.w("warning");
Logger.v("verbose");
Logger.i("information");
Logger.wtf("What a Terrible Failure");

支持字符串格式参数:

Logger.d("hello %s", "world");

支持集合(仅可用于调试日志):

Logger.d(MAP);
Logger.d(SET);
Logger.d(LIST);
Logger.d(ARRAY);

JSON和XML支持(输出将处于调试级别):

Logger.json(JSON_CONTENT);
Logger.xml(XML_CONTENT);

效果展示:

将日志保存到文件中,请参照官网。

 

Logger工作原理图(来自GitHub):

 解决在Android Studio 3.0以上的版本中Logger无法对齐的问题

/**
 * 自定义LogStrategy,解决AS3.0以上版本中日志无法对齐的问题
 */
public class MyLogcatLogStrategy implements LogStrategy {
    @Override
    public void log(int priority, @Nullable String tag, @NonNull String message) {
        Log.println(priority, randomKey() + tag, message);
    }

    private int last;

    private String randomKey() {
        int random = (int) (10 * Math.random());
        if (random == last) {
            random = (random + 1) % 10;
        }
        last = random;
        return String.valueOf(random);
    }
}

// Logger 初始化时,将 MyLogcatLogStrategy 类实例化,并设置到 LogStrategy 中
PrettyFormatStrategy strategy = PrettyFormatStrategy.newBuilder()
        .logStrategy(new LogCatStrategy())
        .tag("TAG")//(可选)这里也可以设置全局TAG
        .build();
Logger.addLogAdapter(new AndroidLogAdapter(strategy));

收获

// 第一个元素代表堆栈顶,它是该序列中最新的方法调用。最后一个元素代表堆栈底,是该序列中最旧的方法调用。
StackTraceElement[] trace = Thread.currentThread().getStackTrace();

例子:

public class A {
    public static void main(String[] args) {
        B b = new B();
        b.log();
    }
}

class B {
    public void log() {
        C c = new C();
        c.log();
    }
}

class C {
    private int MIN_STACK_OFFSET = 1;
    private int methodCount = 2;

    public void log() {
        StringBuilder builder;
        // 第一个元素代表堆栈顶,它是该序列中最新的方法调用。最后一个元素代表堆栈底,是该序列中最旧的方法调用。
        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
        System.out.println("trace.length:" + trace.length);
        // 用来缩进
        String level = "";

        int stackOffset = getStackOffset(trace);

        for (int i = trace.length - 1; i >= 0; i--) {
            builder = new StringBuilder();
            StackTraceElement e = trace[i];

            builder.append(' ')
                    .append(level)
                    .append(getSimpleClassName(e.getClassName()))
                    .append(".")
                    .append(e.getMethodName())
                    .append(" ")
                    .append(" (")
                    .append(e.getFileName())
                    .append(":")
                    .append(e.getLineNumber())
                    .append(")");
            level += "   ";
            System.out.println(builder.toString());
        }
    }

    private static String getSimpleClassName(@NonNull String name) {
        int lastIndex = name.lastIndexOf(".");
        return name.substring(lastIndex + 1);
    }
}

结果图:

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

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

参考Logge源码改进代码:

  1.实现自定义输出的堆栈行数。

  2.实现从某一位置开始输出。

 

posted on 2017-11-29 17:39  JonSnows  阅读(761)  评论(0)    收藏  举报

导航