为什么需要日志结构

假设咱们需要用三方库,那就意味着依据原生计划会存在一些痛点,咱们不得不运用某种手段去解决这些痛点。那原生 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());

装备比较简略,能够装备控制台、文件输出。

三款 Android 日志框架对比「Logger、Timber、XLog」

日志输出格局仍是挺漂亮的,能够直接输出 Collection、json、xml 类型数据,但是不能自界说输出格局。 日志能够保存到磁盘,但不能装备文件相关战略(文件名、备份、删去等),能够理解为,有存储文件功用,但不多。

前面也说到,这个结构十分轻量,只要十多个类,它能够满意咱们根本的日志需求,将日志保存到文件,且不会丢掉。日志输出格局也还不错。但相对而言,关于个性化的支持就比较短缺了。比方,输出格局是不能简略自界说的,比方我假设只想输出一行日志,不输出表格线,那就会比较费事。

主观打分:

目标 分数
Stars 13K
轻量
集本钱钱
日志留存
日志办理战略
输出格局规整
便利挑选 ⭕️
代码方位定位 ⭕️
装备灵敏

Timber

三款 Android 日志框架对比「Logger、Timber、XLog」

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());

一个很优异的日志结构,假设你需要输出到文件、云端,那能够界说自己的FileLoggingTreeCloudFileTree,然后初始化时用 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+。

日志输出:

三款 Android 日志框架对比「Logger、Timber、XLog」

能够看到这个输出格局与 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那么丰厚,也没有默许的文件输出完结。没有最好的,只要最合适的,我们能够依据自己的需求来挑选开源的结构,也欢迎我们多多沟通!