# TimberTree **Repository Path**: daizhufei/TimberTree ## Basic Information - **Project Name**: TimberTree - **Description**: 开源日志库Timber的Tree的实现。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-13 - **Last Updated**: 2026-02-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 介绍 这是一个使用 [tony19/logback-android](https://github.com/tony19/logback-android) 为 [JakeWharton/timber](https://github.com/JakeWharton/timber) 实现的Tree,结合了`Timber`可以自动使用当前类作为`tag`以及`logback`记录日志到文件的强大功能的各自优点,用于在`Android`中可以方便的将日志写到控制台以及文件中。 # 本项目提供的功能 - `FileTree` 基于`logback`实现的写文件的Tree。 - 文件保存位置为应用的外部私有专用目录:`/sdcard/Android/data/packageName/files`下: - `logs` 目录 - `bugs` 目录 - `VERBOSE`、`DEBUG`级别的日志不保存。 - `INFO`以及更高级别的日志保存到`logs`目录。 - `ERROR`以及更高级别的日志同时还保存到`bugs`目录中,方便一眼看出有没有出现过`bug`。 - 当前`logback.xml`配置为: - 保存历史30天 - 总日志大小600MB - `logs`日志异步保存。 - `bugs`日志在调用线程保存,以方便出现异常时更及时保存异常信息,避免异常信息丢失。 - 日志文件按天保存 - `logs`文件:log_2025_10_13.log - `bugs`文件:bug_2025_10_13.log - 日期使用时区为:`Asia/Shanghai`,方便在中国时间新的一天开始时创建新的日志文件。 - 提供获取日志目录的属性: - `logFilesDir` - `bugFilesDir` - 日志格式示例: ```bash 2025-10-13 16:03:43.094 INFO MainActivity:[main] onCreate() ``` - 如果有配置不满足,可以在自己的项目的`asserts`目录中提供自己的`logback.xml`,以覆盖默认配置,对于`logback.xml`配置,可查看:[logback-android Wiki](https://github.com/tony19/logback-android/wiki),另外也可以参考 [logback](https://github.com/qos-ch/logback) 官方网站。 - `DebugTreeWithThreadName`,用于打印日志到控制台,继承自`Timber`中的`DebugTree`,只是简单的在消息中添加了线程信息,示例如下: ```bash [main] onCreate() ``` - `TimberUtil`,提供了记录当前函数的方法 - `logMethodName()` 记录当前函数名,并以当前类名作为`tag`。 - `logMethodName(this: Any)` 记录当前函数名,并以`this`对象的类名作为`tag`,比如在`BaseActivity`中记录所有的生命周期函数。 - `TimberInitializer` 提供了Timber的初始化,以方便懒人可以更懒,依赖我们的库后就可以直接使用,无需任何配置。 # 依赖配置 ```kotlin implementation("cn.android666:timber-tree:1.0.3") ``` 如有需要,也可以对本项目依赖的库使用别的版本: ```kotlin implementation("com.jakewharton.timber:timber:5.0.1") implementation("org.slf4j:slf4j-api:2.0.7") implementation("com.github.tony19:logback-android:3.0.0") ``` # 注意 本库使用`org.jetbrains.kotlin.android`插件的版本为`2.2.20`,当我在别的项目中使用这个库时,使用的版本为`2.0.21`,在编译时就会报`source must not be null`异常,我不知道为什么会出现这个异常,我尝试过把库里面的所有代码全部删除,然后再发布`aar`,但是只要引用了这个库就会报`source must not be null`异常,鬼异的很,而且你也不知道是什么地方配置不对导致的。解决办法就是把使用这个库的项目的`org.jetbrains.kotlin.android`插件的版本也设置为`2.2.20`就没问题了。 奇怪的是,我看到`Timber`库配置的`org.jetbrains.kotlin.android`插件的版本也是`2.2.20`,但是我的项目使用`2.0.21`或别的版本来运行都没问题。 # 使用 1. 初始化 使用App Startup库完成初始化(具体可参考[官网](https://developer.android.google.cn/topic/libraries/app-startup?hl=zh-cn)或我的[博客](https://blog.csdn.net/android_cai_niao/article/details/153677674)),这部分是自动完成的,以方便开箱即用,无需任何配置。`TimberInitializer`实现如下: ```kotlin class TimberInitializer : Initializer { override fun create(context: Context) { Timber.plant(DebugTreeWithThreadName(), FileTree(context)) val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { t, e -> Timber.e(e, "未捕获的异常") defaultUncaughtExceptionHandler?.uncaughtException(t, e) } Timber.d("Timber initialized by Startup from Lib") } override fun dependencies(): List>> { return emptyList() } } ``` 这个实现在写一些小Demo的时候特别有用,只要依赖了我们的库就可以使用`Timber`来记录日志了,无需要任何配置。由于在库里面无法访问项目app的`BuildConfig.DEBUG`,所以这里写死了控制台和文件日志全部种上了,如果是在正式的项目里面,还是要自己写一下,一般release环境下不打印日志到控制台,所以可以通过项目的`BuildConfig.DEBUG`来控制日志输出,在自己的项目中添加自定义初始化逻辑,示例如下: 添加App Startup依赖: ```groovy dependencies { implementation("androidx.startup:startup-runtime:1.2.0") } ``` 实现自己的初始化逻辑: ```kotlin class MyTimberInitializer : Initializer { override fun create(context: Context) { if (BuildConfig.DEBUG) { Timber.plant(DebugTreeWithThreadName(), FileTree(context)) } else { Timber.plant(FileTree(context)) } val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { t, e -> // 参数t为线程,表示当前发生异常的线程,这里的调用也是由t线程调用的 Timber.e(e, "未捕获的异常") defaultUncaughtExceptionHandler?.uncaughtException(t, e) } Timber.d("Timber initialized by Startup from app") } override fun dependencies(): List>> { // 如果没有依赖其他 Startup 初始化器,就返回空列表 return emptyList() } } ``` 然后配置清单文件: ```kotlin ``` 2. 使用`Timber`记录日志: ```kotlin // verbose和debug级别的日志:打印到控制台 Timber.v("verbose") Timber.d("debug") // info和warning级别的日志:打印到控制台 + 写到日志文件 Timber.i("info") Timber.w("warning") // error和wtf级别的日志:打印到控制台 + 写到日志文件 + 写到异常文件 Timber.e(Exception("I'm sorry!")) Timber.e("error") Timber.wtf("wtf") // 获取日志文件目录,方便上传日志时使用 val fileTree = Timber.forest().find { it is FileTree } as FileTree Timber.i("logDir=${fileTree.logFilesDir}") Timber.i("bugDir=${fileTree.bugFilesDir}") ``` 3. 自动记录Activity生命周期: ```kotlin open class BaseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) TimberUtil.logMethodName(this) } // ...更多的生命周期方法 override fun onDestroy() { super.onDestroy() TimberUtil.logMethodName(this) } } ``` 其它`Activity`只要继承`BaseActivity`就可以自动记录生命周期方法,方便了解`Activity`的状态。 如果只是需要以当前类名为`tag`打印当前函数名,则使用`TimberUtil.logMethodName()`即可。