Logger 介绍
在日常开发中,日志是必不可少的一步,数据查看、bug 追踪、数据收集等都需要用到日志,Android 系统提供了 Log 类来实现,但是每次都要输入一个 TAG, 会非常的麻烦。所以你可以自己封装一个 Log 框架,也可以使用一些开源日志框架,比如:Timer、XLog、Logger 等,在这里主要介绍一下 Logger。
Logger 是 Orhan Obut 搞的, Simple, pretty and powerful logger for android.
Logger 支持多种类型:
String,String format,数组,集合,XML和JSON,同时也可将日志存储到文件,也可输出线程方法等详细信息
Logger 使用
1. Gradle 依赖:
implementation 'com.orhanobut:logger:2.2.0'
复制代码
2. 添加 Adapter
Logger.addLogAdapter(new AndroidLogAdapter());
复制代码
接下来就是可以直接使用了
Logger.d("message");
复制代码
默认输出 Log 以及所在类名,方法名,行号,线程等相关信息。如果不想显示除 Log 外的其他信息,可以对 Adapter 进行相关设置,
FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
.showThreadInfo(false) // 展示线程信息
.methodCount(5) // 展示调用的方法个数,默认是 2
.methodOffset(0) // 跳过堆栈中的方法个数, 默认是 0
.tag("My custom tag") // TAG 内容. 默认是 PRETTY_LOGGER
.build();
Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy));
复制代码
显示如下,如果 methodOffset 为1,则不展示 MainActivity.onCreate(),只显示其他 4 个。
如果需要将日志存储到本地文件,则需要使用 DiskLogAdapter, 同时需要声明存储权限,Logger 默认生成 csv 文件,存储在 /storage/emulated/0/logger 目录下,
Logger.addLogAdapter(new DiskLogAdapter());
复制代码
如果针对不同的页面 Logger 的配置不同, 可以使用 Logger.clearLogAdapters(), 然后进行重新配置。
3. 其他类型
message 除了是 String 类型,还可以是集合,数组,
Logger.t("tag").e("Custom tag for only one use");
Logger.json("{ \"key\": 3, \"value\": something}");
Logger.d(Arrays.asList("foo", "bar"));
Logger.d(new int[]{2,3,19,4});
Logger.d("");
Map<String, String> map = new HashMap<>();
map.put("key", "value");
map.put("key1", "value2");
Logger.d(map);
Logger.d("message %s", " erro");
复制代码
Logger 源码分析
1. 调用顺序
Logger 最终调用的还是 Log.println(int priority, String tag, String msg) 方法,以 Logger.d() 为例, 一步步查看
Logger.d("message");
指向 LoggerPrinter.d() 方法, 指向 log(), 由于可以同时添加多个 adapter, 所以在这里要进行一次 for 循环,遍历所有的 adapter
以 AndroidLogAdapter 为例,指向 AndroidLogAdapter 的 log() 方法, 最终使用系统 Log.println() 输出日志。
2. 存储分析
上传客户端日志,对于分析 app 运行情况可用户使用习惯是至关重要的一步,但是 Logger 的存储路径试固定的,没有提供相关的 api 进行设置,所以可以通过分析其中的原理,然后自定义一个 adapter. 对于这里的路径我建议存储在 /Android/data/包名, 因为此路径不需要获取用户权限,可以直接使用。
通过 new DiskLogAdapter(), 在其构造方法中 CsvFormatStrategy 使用 Builder 模式 创建了一个 CsvFormatStrategy 实例, 在 builder() 可以看到具体的路径,因为一旦在子线程中操作,Handler 需要手动启动 Looper, 所以这里 通过 HandlerThread 获取 Looper 传递给 Handler, 通过 DiskLogStrategy.WriteHandler 创建 Handler, 将将文件路径传递给 DiskLogStrategy.WriteHandler, 同时通过构造方法生成 DiskLogStrategy 对象,将 handler 传递给 DiskLogStrategy, 当输出 Log 时调用 DiskLogStrategy 的 log() 方法,通过 log() 方法中 handler 将 message 发送出去, 然后交给 handler 处理,存储到 DiskLogStrategy.WriteHandler 中的路径。
第一次来来掘金发博客,欢迎指正
end