为什么需要日志结构
假设咱们需要用三方库,那就意味着依据原生计划会存在一些痛点,咱们不得不运用某种手段去解决这些痛点。那原生 Logcat 存在哪些痛点,咱们来聊一聊:
- 日志不能耐久化,缓冲区日志很容易丢掉
- 假设系统压力大有可能会导致日志折叠、丢掉
- 无法界说日志输出格局,如:json、xml
- 无法快速定位日志输出时的代码方位
其实前两个才是首要痛点,日志不丢掉,有途径能获取到已打印的日志这是咱们最根底的需求。只需日志不丢掉,其他问题说实话都能够克服。
好,痛点知道了,那咱们就要挑选一个日志计划去解决这些痛点。不过 Github 上的日志结构有很多,选哪个呢?那无妨先聊下,咱们期望日志结构能提供哪些功用。
期望中的日志结构才能
- 计划轻量,入侵度越低越好
- 集成便利、便利,不应该在集成日志库上花费太多时间
- 日志留存,至少能够存储到本地磁盘
- 文件战略办理,处理文件备份、删去等战略
- 输出格局规整,最好能自界说输出格局
- 便利挑选,可依据日志等级、标签挑选
- 代码方位定位,可从 IDE 直接调到相关代码方位
- 装备丰厚,给开发者高度的自由
假设日志结构能到达以上要求,那咱们以为这个日志结构就比较不错了,那接下来咱们就对比下 Github 上的这几款高星日志结构 Logger、Timber、XLog。
以上我没有说到功用,其实仔细想来,在日志结构里,功用是一个伪需求。为什么?咱们多数日志在正式版本上并不会打印,正式版本能打印的都是比较少的要害日志。而且,在 Android 里,咱们说到的功用目标一般都是针对主线程,由于主线程的功用会反应到界面上,能让用户感知到,所以主线程的工作效率一定要高。而耗时操作,比方说这里的日志 IO 操作,其实都在主线程履行,只需功用不要太差就行。
Logger
Logger orhanobut/logger是一个比较前期的日志结构,积累到现在的人气超高,拥有将近 14K 的 Star。这个库十分轻量,满打满算整个库只要 13 个类,你敢信!
集成比较简略,只需要指定输出日志的 Adapter
FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
.showThreadInfo(true) // (Optional) Whether to show thread info or not. Default true
.methodCount(1) // (Optional) How many method line to show. Default 2
// .methodOffset(3) // (Optional) Skips some method invokes in stack trace. Default 0
.tag("My custom tag") // (Optional) Custom tag for each log. Default PRETTY_LOGGER
.build();
Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy));
Logger.addLogAdapter(new DiskLogAdapter());
装备比较简略,能够装备控制台、文件输出。
日志输出格局仍是挺漂亮的,能够直接输出 Collection、json、xml 类型数据,但是不能自界说输出格局。 日志能够保存到磁盘,但不能装备文件相关战略(文件名、备份、删去等),能够理解为,有存储文件功用,但不多。
前面也说到,这个结构十分轻量,只要十多个类,它能够满意咱们根本的日志需求,将日志保存到文件,且不会丢掉。日志输出格局也还不错。但相对而言,关于个性化的支持就比较短缺了。比方,输出格局是不能简略自界说的,比方我假设只想输出一行日志,不输出表格线,那就会比较费事。
主观打分:
目标 | 分数 |
---|---|
Stars | 13K |
轻量 | |
集本钱钱 | |
日志留存 | |
日志办理战略 | ❌ |
输出格局规整 | |
便利挑选 | ⭕️ |
代码方位定位 | ⭕️ |
装备灵敏 |
Timber
Timber JakeWharton/timber是 Jake Wharton 大神出品。他原话是:老是要把打日志这部分代码拷来拷去太费事了,所以以库的方法开源出来。Timber 与其他日志库不太相同的是它并没有提供很多功用,而是搭建了一个日志功用结构,我们能够依照自己的需求来构建自己的Tree
。
前面咱们说 Logger 库很简略只要十几个类,而 Timber 更简略,只要一个类文件,运用 Kotlin 语言。不过这些代码首要是结构代码,只要一个完结类DebugTree
用来完结原生控制台输出日志,能够自已自界说输出格局,能够不必指定 TAG,默许 TAG 为类名,来看看如何运用。
if (BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
} else {
Timber.plant(new CrashReportingTree());
}
Timber.i("A button with ID %s was clicked to say '%s'.", button.getId(), button.getText());
一个很优异的日志结构,假设你需要输出到文件、云端,那能够界说自己的FileLoggingTree
、CloudFileTree
,然后初始化时用 Timber.plant()
办法,把自定的 Tree “栽培”下去就行。
假设你需要将日志输出到文件的完结,那这个库是不支持的。它能够将日志多种输出方法会集成Tree
,经过Forest
去统一办理。
目标 | 分数 |
---|---|
Stars | 10K |
轻量 | |
集本钱钱 | |
日志留存 | ❌ |
日志办理战略 | ❌ |
输出格局规整 | |
便利挑选 | ⭕️ |
代码方位定位 | ❌ |
装备灵敏 |
XLog
轻量、漂亮强大、可扩展的 Android 和 Java 日志库,可一起将日志打印在如 Logcat、Console 和文件中。假设你愿意,你能够将日志打印到任何地方。这是 XLog 的毛遂自荐。elvishew/xLog: Android logger, pretty, powerful and flexible, log to everywhere, save to file, all you want is here. (github.com)
运用下来感觉的确如它自己所述:轻量、漂亮、强大、可扩展,它的星没有前两者那么多,但也不少,2.9K+。
日志输出:
能够看到这个输出格局与 Logger 仍是挺像的,不同的是 XLog 能够自界说输出格局,Logger 不行。就比方这些花里胡哨的 boder,在 XLog 里能够便利装备,而 Logger 则费事不少。
装备:
LogConfiguration config = new LogConfiguration.Builder()
.logLevel(BuildConfig.DEBUG ? LogLevel.ALL // 指定日志等级,低于该等级的日志将不会被打印,默以为 LogLevel.ALL
: LogLevel.NONE)
.tag("MY_TAG") // 指定 TAG,默以为 "X-LOG"
.enableThreadInfo() // 答应打印线程信息,默许制止
.enableStackTrace(2) // 答应打印深度为 2 的调用栈信息,默许制止
.enableBorder() // 答应打印日志边框,默许制止
.jsonFormatter(new MyJsonFormatter()) // 指定 JSON 格局化器,默以为 DefaultJsonFormatter
.xmlFormatter(new MyXmlFormatter()) // 指定 XML 格局化器,默以为 DefaultXmlFormatter
.throwableFormatter(new MyThrowableFormatter()) // 指定可抛出反常格局化器,默以为 DefaultThrowableFormatter
.threadFormatter(new MyThreadFormatter()) // 指定线程信息格局化器,默以为 DefaultThreadFormatter
.stackTraceFormatter(new MyStackTraceFormatter()) // 指定调用栈信息格局化器,默以为 DefaultStackTraceFormatter
.borderFormatter(new MyBoardFormatter()) // 指定边框格局化器,默以为 DefaultBorderFormatter
.addObjectFormatter(AnyClass.class, // 为指定类型增加对象格局化器
new AnyClassObjectFormatter()) // 默许运用 Object.toString()
.addInterceptor(new BlacklistTagsFilterInterceptor( // 增加黑名单 TAG 过滤器
"blacklist1", "blacklist2", "blacklist3"))
.addInterceptor(new MyInterceptor()) // 增加一个日志拦截器
.build();
Printer androidPrinter = new AndroidPrinter(true); // 经过 android.util.Log 打印日志的打印器
Printer consolePrinter = new ConsolePrinter(); // 经过 System.out 打印日志到控制台的打印器
Printer filePrinter = new FilePrinter // 打印日志到文件的打印器
.Builder("<日志目录全途径>") // 指定保存日志文件的途径
.fileNameGenerator(new DateFileNameGenerator()) // 指定日志文件名生成器,默以为 ChangelessFileNameGenerator("log")
.backupStrategy(new NeverBackupStrategy()) // 指定日志文件备份战略,默以为 FileSizeBackupStrategy(1024 * 1024)
.cleanStrategy(new FileLastModifiedCleanStrategy(MAX_TIME)) // 指定日志文件铲除战略,默以为 NeverCleanStrategy()
.flattener(new MyFlattener()) // 指定日志平铺器,默以为 DefaultFlattener
.writer(new MyWriter()) // 指定日志写入器,默以为 SimpleWriter
.build();
XLog.init( // 初始化 XLog
config, // 指定日志装备,假设不指定,会默许运用 new LogConfiguration.Builder().build()
androidPrinter, // 增加恣意多的打印器。假设没有增加任何打印器,会默许运用 AndroidPrinter(Android)/ConsolePrinter(java)
consolePrinter,
filePrinter);
XLog 的装备十分丰厚、灵敏,所以它比前两个库类要多一些,50+左右,也算十分轻量。假设你不想自界说装备,只需要XLog.init(LogLevel.ALL);
即可完结初始化,全部运用 XLog 缺省装备。
XLog 的装备十分多,首要分为几大类,咱们来看下装备接口的目录结构:
├── formatter
│ ├── Formatter.java // 日志输出格局化接口
│ ├── border
│ │ └── BorderFormatter.java // 装修线格局化接口
│ ├── message
│ │ ├── json
│ │ │ └── JsonFormatter.java // json 格局化接口
│ │ ├── object
│ │ │ └── ObjectFormatter.java // 对象格局化接口
│ │ ├── throwable
│ │ │ └── ThrowableFormatter.java // 反常格局化接口
│ │ └── xml
│ │ └── XmlFormatter.java // xml 格局化接口
│ ├── stacktrace
│ │ └── StackTraceFormatter.java // 仓库格局化接口
│ └── thread
│ └── ThreadFormatter.java // 线程id、name 输出格局化
├── interceptor
│ └── Interceptor.java // 拦截器
└── printer
│ └── Printer.java //日志输出接口
├── file
│ ├── backup
│ │ ├── BackupStrategy.java // 日志备份战略接口
│ │ └── BackupStrategy2.java
│ ├── clean
│ │ └── CleanStrategy.java // 日志铲除战略接口
│ ├── naming
│ │ └── FileNameGenerator.java // 文件命名接口
│ └── writer
│ └── Writer.java // 文件输入接口
└── flattener
└── LogFlattener.java // 日志字段摆放接口
装备首要分为以下几类:
- 日志打印
- 日志格局化
- 文件输入
- 文件备份战略
- 文件铲除战略
- 日志字段摆放
XLog 的架构思想与 Timber 差不多是共同的,日志结构依据功用接口办理所有日志输出,结构自身的日志输出完结相同是依据结构界说的接口。不同的是,XLog 接口界说得更细致,有二十多个接口。一起,结构自身也有所有接口的全部默许完结,这些完结就已经能够满意部分开发者。假设不满意,那 XLog 的高可装备性就体现出来了,你能够依据结构界说自己的完结。
public static void init(LogConfiguration logConfiguration, Printer... printers) {
......
sPrinter = new PrinterSet(printers);
sLogger = new Logger(sLogConfiguration, sPrinter);
}
此办法是初始化进口,假设你不想用默许的文件输出方法,你能够依据Printer
接口重新完结一个CustomFilePrinter
。或者你想将日志输出到云端,能够界说个CloudLogPrinter
,然后初始化时运用自界说的Printer
,像这样:
XLog.init(
config,
androidPrinter,
CustomFilePrinter(),
CloudLogPrinter()
);
别的,假设你的工程里有其他第三方日志或 Android 原生日志输出,也期望这些地方的日志也能输出到文件,XLog能够提供一个简略的方法,让你不需要改代码便能输出日志到文件。
// Intercept all logs(including logs logged by third party modules/libraries) and print them to file.
LibCat.config(true, filePrinter);
这个操作仍是蛮实用的吧?
XLog 的其他装备细节就不跟我们细聊了,其装备才能便是上述那几类,代码逻辑架构很明晰,逻辑也比较简略我们能够自行了解,总之是一个比较优异的日志库。
老规矩,打个分:
目标 | 分数 |
---|---|
Stars | 2.9K |
轻量 | |
集本钱钱 | |
日志留存 | ⭕️ |
日志办理战略 | |
输出格局规整 | |
便利挑选 | ⭕️ |
代码方位定位 | ⭕️ |
装备灵敏 |
关于 Android 比较盛行的这三个日志结构对比到这边就差不多了,Logger 相对而言比较老了,关于现在的项目可能会有些水土不服。别的两个都比较优异,差异便是Timber的装备没有XLog那么丰厚,也没有默许的文件输出完结。没有最好的,只要最合适的,我们能够依据自己的需求来挑选开源的结构,也欢迎我们多多沟通!