简要
OTLogger是一个Android日志库,官方Log 高替版。允许同时把日志 输出到Logcat 和 保存到磁盘。因其内部实现采用策略的设计模式,所以使用者可以根据自己的需求轻松定制该库的每个模块,包括日志输出格式、日志保存方式、捕获异常日志等。
简单使用
在 root/build.gradle 中添加
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
在项目中添加依赖:release 见最新版本号
implementation 'com.github.oi-october:OTLogger:1.1.0'
使用OTLogger
//使用 QTlogger
LogUtils.v(TAG, "V级别 日志")
LogUtils.d(TAG, "D级别 日志")
LogUtils.i(TAG, "I级别 日志")
LogUtils.w(TAG, "W级别 日志")
LogUtils.e(TAG, "E级别 日志")
就是这样简单,如同 Log 一样直接使用即可。默认会把日志打印到控制台,其输出的日志格式与Log
的格式一致。
定制属于你的日志
以上是OTLogger最简单的使用方式,但是OTLogger能提供的并不仅仅局限于此,你可以基于OTLogger定制一个想要的日志库。 其中定制的内容包括日志输出格式,日志保存策略,异常日志捕获,日志输出等级等功能。如果你认为上面的功能还不能满足你的需求,你完全可以自己实现OTLogger中对应的模块。
既然要定制,我们先了解OTLogger的实现机制:
上图可以看到,LogUtils下调用的就是Logger,所以我们定义属于自己的日志无非就是定义一自己的Logger。而自定义一个Logger的常规设置是:
val logger = Logger.Builder()
.setLogcatPrinter(LogcatDefaultPrinter()) //设置 Logcat printer
.setLogTxtPrinter(LogTxtDefaultPrinter()) //设置 LogTxt printer
.setCrashStrategy(DefaultCrashStrategyImpl()) //设置 crash ,捕获异常日志
.build()
LogUtils.setLogger(logger)
Logger下分为三层:
Printer 层 :打印机层
负责把日志打印到指定的位置,无论是把日志输出到Logcat还是磁盘,都是通过打印机(Printer)进行输出。目前已经定义有两种类型的打印机:
1. BaseLogcatPrinter: Logcat打印机
负责打印日志到Logcat, 是一个抽象类。当我们需要定制自己的Logcat Printer 的时候,可以继承BaseLogcatPrinter
并重写内部的方法即可:
LogcatDefaultPrinter
: OTLogger内部已经实现的 Logcat Printer
/**
* 默认Loacat 打印机
* @property printable 是否打印日志到Logcat,默认 true
* @property minLevel 最小日志输出级别, 默认 LogLevel.V
* @property formatStrategy 日志格式策略, 默认 LogcatDefaultFormatStrategy
*/
open class LogcatDefaultPrinter(
val printable: Boolean = true,
val minLevel: LogLevel = LogLevel.V,
val formatStrategy: LogcatDefaultFormatStrategy = LogcatDefaultFormatStrategy()
) : BaseLogcatPrinter()
可以看到,输出到Logcat 的日志所有的行为在BaseLogcatPrinter
内部实现,包括日志级别,日志格式等。如果你认为LogcatDefaultPrinter
已经无法满足你的需求,请重写BaseLogcatPrinter
。
2.BaseLogTxtPrinter: 磁盘打印机
负责打印日志到磁盘文件中,是一个抽象类。当我们需要定制自己的 LogTxt Printer 的时候,可以继承并重写BaseLogTxtPrinter
内部的方法即可。
LogTxtDefaultPrinter
:OTLogger内部已经实现的 LogTxt Printer
/**
* 默认日志文件打印机
* @property printable 是否写入到文件 ,默认 true
* @property minLevel 最低输出日志, 默认 LogLevel.V
* @property formatStrategy 日志格式策略, 默认 LogTxtDefaultFormatStrategy
* @property diskStrategy 文件管理策略,默认 TimeLogDiskStrategyImpl
*/
open class LogTxtDefaultPrinter(
val printable: Boolean = true,
val minLevel: LogLevel = LogLevel.V,
val formatStrategy: LogTxtDefaultFormatStrategy = LogTxtDefaultFormatStrategy(),
val diskStrategy: BaseLogDiskStrategy = TimeLogDiskStrategyImpl()
) : BaseLogTxtPrinter()
Format 层:日志格式层
该层定义了日志输出的格式,通过继承BaseFormatStrategy
实现,每个Printer都包含一个FormatStrategy,所以每个Printer 都可以拥有自己的日志格式。
OTLogger已经实现两种日志格式,DefaultFormatStragety
和 PrettyFormatStrategy
。:
使用DefaultFormatStragety
格式
该日志格式和官方默认Log输出格式(旧版)保持一致,是默认日志格式策略:
val logger = Logger.Builder()
//指定 Logcat 使用日志格式:LogcatDefaultFormatStrategy
.setLogcatPrinter(LogcatDefaultPrinter(formatStrategy = LogcatDefaultFormatStrategy()))
//指定 Logtxt 使用日志格式:LogTxtDefaultFormatStrategy
.setLogTxtPrinter(LogTxtDefaultPrinter(formatStrategy = LogTxtDefaultFormatStrategy()))
.build()
LogUtils.setLogger(logger)
日志格式输出如下:
使用 PrettyFormatStrategy
格式
val logger = Logger.Builder()
//指定 Logcat 使用日志格式:LogcatPrettyFormatStrategy
.setLogcatPrinter(LogcatDefaultPrinter(formatStrategy = LogcatPrettyFormatStrategy()))
//指定 Logtxt 使用日志格式:LogTxtPrettyFormatStrategy
.setLogTxtPrinter(LogTxtDefaultPrinter(formatStrategy = LogTxtPrettyFormatStrategy()))
.build()
LogUtils.setLogger(logger)
输出日志格式如下:
注意: 上面每一种日志格式 Logcat 和 LogTxt 个有一个实现类
比如:LogcatDefaultFormatStrategy 和 LogTxtDefaultFormatStrategy为什么会这样?
- 输出到Logcat的日志本质上还是调用
Log.println(int priority, String tag, String msg)
函数进行打印,所以我们无法定制输出的时间、PID 等信息;只能定制其中的 msg 信息,所以专属Logcat的BaseFormatStrategy.format()
返回的String对应的msg参数。- 相对的,LogTxt的
BaseFormatStrategy.format()
返回的String对应打印到磁盘的整条日志信息。
如果我们希望定义自己的日志打印格式,可以继承BaseFormatStrategy
并实现其内部format
方法
/**
* @param logLevel 日志等级
* @param tag 日志tag
* @param msg 日志内容
* @param thr 异常日志内存
* @param param 预留拓展参数,方便更好定制日志格式。
* @return 日志输出格式
*/
abstract fun format(logLevel: LogLevel,
tag:String?, msg:String?,
thr: Throwable?,
param:Any? = null):String
Disk层:磁盘管理层
该层管理了所有的日志文件,只有 LogTxt Printer才会使用到,主要解决的问题:
每一行日志打印打印到哪个文件中?
何时分配一个新的日志文件?
何时回收、如何回收旧的日志文件?
该层通过通过继承抽象类BaseLogDiskStrategy
实现。目前已经实现的DiskStrategy
:
TimeLogDiskStrategyImpl
:时间管理策略
按时间管理日志(默认磁盘管理策略)
- 默认每个日志文件保存七天,
- 默认按照小时创建日志文件
- 默认文件名 log_年_月_日_时间段.log 。 eg:otLog_2023_02_12_15_16.log ,这里的 15_16 表示该文件储存 15点到 16点的日志。
其构造方法如下:
```kotlin
/**
* @param logDirectory 日志文件夹
* @param logKeepOfDay 日志保存天数
* @param logSegment 创建日志文件间隔,默认每个小时创建一份新的日志文件
*/
open class TimeLogDiskStrategyImpl(
val logDirectory: String = defaultLogDir,
val logKeepOfDay: Int = 7,
val logSegment:LogTimeSegment= LogTimeSegment.ONE_HOUR
) : BaseLogDiskStrategy()
```
FileLogDiskStrategyImpl
:文件管理策略
按照文件大小管理磁盘日志
- 默认每个日志文件5MB,参考[`logFileStoreSizeOfMB`]
- 默认日志文件夹最大可容纳 100M日志,超过[`logDirectoryMaxStoreSizeOfMB`]会按照时间顺序删除旧的日志,直到低于预定值
- 默认文件名 otLog_年_月_日_时_分_秒.log 。 eg: otLog_2023_02_12_16_28_56.log
- 每个日志写满了会创建一个新的日志文件
- 为了保护系统,以上都要当系统可用空闲空间大于最低限制的空闲空间[`minFreeStoreOfMB`]时,才会创建新的日志文件。
其构造方法如下:
/**
* @param logDirectory 日志文件夹
* @param minFreeStoreOfMB 最小空闲空间(单位MB),当系统最小空闲存储空间低于该值时,不再创建新的日志文件
* @param logDirectoryMaxStoreSizeOfMB 日志文件夹最大的存储容量(单位MB),所有的日志文件加起来的大小不得操过该值
* @param logFileStoreSizeOfMB 每个日志文件容量(单位MB),只有上一个日志文件操过容量,才会创建下一个日志文件
*/
open class FileLogDiskStrategyImpl(
val logDirectory: String = defaultLogDir,
val minFreeStoreOfMB: Int = 200,
val logDirectoryMaxStoreSizeOfMB: Int = 100,
val logFileStoreSizeOfMB:Int = 5
) : BaseLogDiskStrategy()
TimeLogDiskStrategyImpl
:文件+时间管理策略
同时具备[FileLogDiskStrategyImpl
] 和 [TimeLogDiskStrategyImpl
] 的部分特性
- 默认日志文件夹最大可容纳 100M日志,超过[`logDirectoryMaxStoreSizeOfMB`]会按照时间顺序删除旧的日志,直到低于预定值;
- 默认文件名 默认文件名 otlog_年_月_日_时间段_时间戳.log 。 eg: otLog_2023_02_12_16_17_11123223423423.log ;
- 每个日志写满了会创建一个新的日志文件,超过日志时间片段,会创建一个新的日志文件进行存储; - 为了保护系统,以上都要当系统可用空闲空间大于最低限制的空闲空间[`minFreeStoreOfMB`]时,才会创建新的日志文件。
其构造函数如下:
/**
* @param logDirectory 日志文件夹
* @param minFreeStoreOfMB 最小空闲空间(单位MB),当系统最小空闲存储空间低于该值时,不再创建新的日志文件
* @param logDirectoryMaxStoreSizeOfMB 日志文件夹最大的存储容量(单位MB),所有的日志文件加起来的大小不得操过该值
* @param logFileStoreSizeOfMB 每个日志文件容量(单位MB),只有上一个日志文件操过容量,才会创建下一个日志文件
* @param segment 创建日志文件间隔,默认每个小时创建一份新的日志文件
*
*/
open class FileAndTimeDiskStrategyImpl(
val logDirectory: String = defaultLogDir,
val minFreeStoreOfMB: Int = 200,
val logDirectoryMaxStoreSizeOfMB: Int = 100,
val logFileStoreSizeOfMB: Int = 5,
val segment: LogTimeSegment = LogTimeSegment.ONE_HOUR
) : BaseLogDiskStrategy()
设置磁盘管理策略
val logger = Logger.Builder()
.setLogTxtPrinter(LogTxtDefaultPrinter(diskStrategy = TimeLogDiskStrategyImpl()) //time
// LogTxtDefaultPrinter(diskStrategy = FileLogDiskStrategyImpl()) //file
// LogTxtDefaultPrinter(diskStrategy = FileAndTimeDiskStrategyImpl()) // file & time
)
.build()
LogUtils.setLogger(logger)
设置日志压缩策略
OTLogger 打印到disk的日志文件默认是不压缩的。在v1.2.0
版本以后,添加了日志压缩策略,其压缩规则是:
- 每当创建一个新的日志文件,遍历所有旧的日志文件进行压缩;
- 当前正在写入的日志文件不压缩;
- 当前已经实现的压缩策略:
/**
* 压缩日志文件成为zip包
*/
class ZipLogCompressStrategy : BaseLogCompressStrategy()
所有的压缩策略必须继承于 BaseLogCompressStrategy
。如果有需要,你可以实现自己的压缩策略。
- 使用压缩策略:
压缩策略必须结合磁盘管理策略一起使用。比如:
//案例1:
val diskStrategy = FileAndTimeDiskStrategyImpl().also {
it.setLogCompressStrategy(logCompressStrategy) //设置压缩策略
}
//案例2:
val diskStrategy= TimeLogDiskStrategyImpl().also {
it.setLogCompressStrategy(logCompressStrategy) //设置压缩策略
}
异常日志捕获
val logger = Logger.Builder()
.setCrashStrategy(DefaultCrashStrategyImpl()) //设置 crash ,捕获异常日志
.build()
LogUtils.setLogger(logger)
通过上面配置,可以捕获app异常,并且把异常信息打印到 Logcat 或者 LogTxt