A lazy logging library.
This is a full logging library with a build in way to log to console, file or any custom place as well as optional extensions to send a log file via mail or show it on the device.
All features are splitted into separate modules, just include the modules you want to use!
Dependency | Version | Infos |
---|---|---|
Compose Multiplatform | 1.7.0 |
based on compose 1.7.1 and material3 1.3.0 |
Note
I try to use as few experimental APIs as possible, but the composeviewer
module does use ExposedDropdownMenuBox
and TopAppBar
which are still marked as experimental in material3 1.3.0
. I will provide new versions as soon as possible if experimental APIs change or become stable.
Module | Dependency | Version |
---|---|---|
core | - | |
Implementations | ||
implementation-lumberjack |
- | |
implementation-timber |
- | |
Logger | ||
logger-console |
- | |
logger-file |
- | |
timber-logger-console |
- | |
timber-logger-file |
- | |
Extensions | ||
extension-feedback |
FeedbackManager | 2.1.0 |
extension-notification |
FeedbackManager | 2.1.0 |
extension-viewer |
FeedbackManager FastScroller |
2.1.0 1.0.0 |
extension-composeviewer |
FeedbackManager | 2.1.0 |
The timber version also depends on following:
Dependency | Version |
---|---|
Timber | 4.7.1 |
SLF4J | 2.0.7 |
logback-android | 3.0.0 |
This library is distributed via maven central.
build.gradle.kts
val lumberjack = "<LATEST-VERSION>"
// core
implementation("io.github.mflisar.lumberjack:core:$lumberjack")
// if you want to use the lumberjack logger
implementation("io.github.mflisar.lumberjack:implementation-lumberjack:$lumberjack")
implementation("io.github.mflisar.lumberjack:logger-console:$lumberjack")
implementation("io.github.mflisar.lumberjack:logger-file:$lumberjack")
// if you want to use the timber logger
// implementation("io.github.mflisar.lumberjack:implementation-timber:$lumberjack")
// implementation("io.github.mflisar.lumberjack:timber-logger-console:$lumberjack")
// implementation("io.github.mflisar.lumberjack:timber-logger-file:$lumberjack")
// Extensions that work with any implementation
implementation("io.github.mflisar.lumberjack:extension-feedback:$lumberjack")
implementation("io.github.mflisar.lumberjack:extension-notification:$lumberjack")
implementation("io.github.mflisar.lumberjack:extension-viewer:$lumberjack")
implementation("io.github.mflisar.lumberjack:extension-composeviewer:$lumberjack")
Module | Info | Description |
---|---|---|
core |
the core module - must always be included | |
Implementations | ||
implementation-lumberjack |
the main implementation of the logger - either this or the timber implementation must always be included | |
implementation-timber |
the main implementation based on timber of the logger - either this or the lumberjack implementation must always be included | |
Logger | ||
logger-console |
optional | a console logger for the lumberjack implementation |
logger-file |
optional | a console logger for the lumberjack implementation |
timber-logger-console |
optional | a console logger for the timber implementation |
timber-logger-file |
optional | a console logger for the timber implementation |
Extensions | ||
extension-feedback |
optional | an extension for easy email feedbacks |
extension-notification |
optional | an extension for exception notification with easy email feedbacks on click |
extension-viewer |
optional | a log viewer based on XML |
extension-composeviewer |
optional | a compsoe log viewer |
1.Setup library - (Lumberjack Style)
class App : Application() {
override fun onCreate() {
// 1) install the implemantion
L.init(LumberjackLogger)
// 2) install loggers
L.plant(ConsoleLogger())
val setup = FileLoggerSetup.Daily(this)
L.plant(FileLogger(setup))
}
}
1.Setup library - (Timber Style)
class App : Application() {
override fun onCreate() {
// 1) install the implemantion
L.init(TimberLogger)
// 2) install loggers (trees)
Timber.plant(ConsoleTree())
val setup = FileLoggingSetup.DateFiles.create(this )
Timber.plant(FileLoggingTree(setup))
}
}
2.Usage
// wherever you want use one of L.* functions for logging
// all the functions are implemented as inline functions with lambdas - this means,
// everything inside the lambda is only executed if the log is really ussed
L.d { "a debug log" }
L.e { "a error log" }
L.e(e)
L.e(e) { "an exception log with an additonal message" }
L.v { "TEST-LOG - Verbose log..." }
L.d { "TEST-LOG - Debug log..." }
L.i { "TEST-LOG - Info log..." }
L.w { "TEST-LOG - Warn log..." }
L.e { "TEST-LOG - Error log..." }
L.wtf { "TEST-LOG - WTF log..." }
// optional tags work like following
L.tag("LEVEL").d { "Tagged log message..." }
// you can log something optionally like following
L.logIf { false }?.d { "This will never be logged because logIf evaluates to false..." }
// manual log levels
L.log(Level.DEBUG) { "Debug level log via L.log instead of L.d" }
3.Filtering Logs (Lumberjack Style)
// typealias LumberjackFilter = (level: Level, tag: String?, time: Long, fileName: String, className: String, methodName: String, line: Int, msg: String?, throwable: Throwable?) -> Boolean
val filter = object : LumberjackFilter {
override fun invoke(
level: Level,
tag: String?,
time: Long,
fileName: String,
className: String,
methodName: String,
line: Int,
msg: String?,
throwable: Throwable?
): Boolean {
// decide if you want to log this message...
return true
}
}
// the filter can then be attached to any logger implementation
val consoleLogger = ConsoleLogger(filter = filter)
val fileLogger = FileLogger(filter = filter)
3.Filtering Logs (Timber Style)
[!TIP] The lumberjack implementation allows you more granular filter options as well as a custom filter for each logger implementation!
TimberLogger.filter = object: IFilter {
override fun isTagEnabled(baseTree: BaseTree, tag: String): Boolean {
// decide if you want to log this tag on this tree...
return true
}
override fun isPackageNameEnabled(packageName: String): Boolean {
// decide if you want to log if the log comes from a class within the provided package name
return true
}
}
4.Other settings
// if desired you can enable/disable all logs completely
// e.g. in a release build like following
// => you probably would want to do this inside the application after the init of Lumberjack
L.enable(BuildConfig.DEBUG)
// Alternatively every logger does support an enabled flag as well
val consoleLogger = ConsoleLogger(enabled = BuildConfig.DEBUG)
val fileLogger = FileLogger(enabled = !BuildConfig.DEBUG, ...)
Supported Platforms
This is a KMP (kotlin multiplatform) library and the provided modules do support following platforms:
Note
iOS would be supported theoretically, but currently I don't know iOS and don't own an apple device - the problem is only that I can't replace ThreadLocal
and StackTraceElement
in a non jvm environment.
Additionally the console logging would need an iOS implementation as well.
If you know how this can be done and want to contribute, that would be much appreciated.
Modules | Android | iOS | jvm | Information |
---|---|---|---|---|
core | β | β | β | |
implementation-lumberjack | β | β | (1) | |
logger-console | β | β | (2) | |
logger-file | β | β | β | |
extension-feedback | β | (3) | ||
extension-notification | β | (3) | ||
extension-viewer | β | (4) | ||
extension-composeviewer | β | β | β | (5) |
- (1) iOS is missing support because I don't know how to handle
ThreadLocal
andStackTraceElement
inside iOS - a pull request would be much appreciated! - (2) iOS is missing a simple console logging function - a pull request would be much appreciated!
- (3) notification and feedback module are android specific modules and therefor only support android
- (4) the viewer module is and older view based module that just supports android based on its nature
- (5) would support iOS if the iOS logger-file module is implemented
Timber Modules
Modules | Android | iOS | jvm | Information |
---|---|---|---|---|
implementation-timber | β | (6) | ||
logger-timber-console | β | (6) | ||
logger-timber-file | β | (6) |
- (6) timber is only supported on android and therefor those modules are android only modules as well
A full demo is included inside the demo module, it shows nearly every usage with working examples.
Extensions
Advanced Stuff
This library fully supports Jack Whartons Timber logging library (v4!). And was even based on it until Lumberjack v6. Beginning with v6 I wrote new modules that work without timber which leads to a smaller and more versitile non timber version. I would advice you to use the non timber versions but if you want to you can simply use the timber modules I provide as well - whatever you prefer.
Why did I do this?
I decided to not use Timber
myself anymore because of following reasons:
Timber
does explicitly rely on non lazy evaluating logging - it was a decision made by Jack Wharton and was the main reason to writeLumberjack
at the beginningTimber
is restrictive regarding class extensions - in v5 I would need access to a field to continue supporting timber inLumberjack
Timber
is considered as working and feature requests and/or pull requests are not accepted if not really necessary - like e.g. my minimal one here.- additionally I always needed to extend the
BaseTree
fromTimber
because of the limiting restrictions of the defaultBaseTree
as well as it was to restrictive to make adjustment in it ( I always had a nearly 1:1 copy of it inside my library here{target=_blank}). This was needed to allow to adjust the stack trace depth so thatLumberjack
will log the correct calling place as a wrapper aroundTimber
.
This lead to my final decision
Lumberjack
does not need Timber
and I provide a way to plug in Timber
into Lumberjack
now - this way using Timber
and Lumberjack
in combination is possible but not necessary anymore.