11

I add the Timber dependency to my Java Core Library Module build.gradle file:

implementation 'com.jakewharton.timber:timber:4.6.0'

Although it did not give an error when gradle synchronizes, I cannot see or use Timber class in the Core Library.

alexpfx
  • 6,412
  • 12
  • 52
  • 88

4 Answers4

6

Timber has a dependency on android.util.Log so it cannot be used in a pure Java module.

Decoupling the library from Android has been proposed but the creator of the library has decided against it. https://github.com/JakeWharton/timber/pull/63

The 5.0.0-SNAPSHOT version of Timber now supports usage in Java modules by using the jdk artifact.

<dependency>
  <groupId>com.jakewharton.timber</groupId>
  <artifactId>timber-jdk</artifactId>
  <version>5.0.0-SNAPSHOT</version>
</dependency>
Joe Rider
  • 148
  • 7
  • found any similar libs? – Benjamin H Oct 01 '18 at 02:45
  • @BenjaminH No, the library module I where I ran into this issue was for an Android app so I converted it to be an Android library module instead of a Java module. I haven't looked for a replacement. – Joe Rider Oct 06 '18 at 17:58
  • That same issue you referenced now says there are two separate artifacts: `timber-jdk` and `timber-android` – arekolek Dec 07 '18 at 12:35
5

If anyone looking at Timber (Without android dependency) for mutli-module android project. Use timber-jdk like below.

In project's build.gradle file.

allprojects {
    repositories {
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
    }
}

In individual module build.gradle file (Example: Domain or remote module)

implementation "com.jakewharton.timber:timber-jdk:5.0.0-SNAPSHOT"

With this you should be able to implement Timber without android framework dependency

Naveen T P
  • 6,955
  • 2
  • 22
  • 29
3

If you have multi-module project, you can use Timber in pure Java/Kotlin with a tiny bit of abstraction involved, no external libraries.

Example with Kotlin and Koin:

In pure kotlin module create a big imposter, Timber.kt:

interface ILogger {
    fun d(message: String)
    fun e(message: String)
    fun e(throwable: Throwable, message: String)
    fun i(message: String)
}

object Timber: ILogger, KoinComponent {

    private val logger: ILogger by inject()

    override fun d(message: String) = logger.d(message)
    override fun e(message: String) = logger.e(message)
    override fun e(throwable: Throwable, message: String) = logger.e(throwable, message)
    override fun i(message: String) = logger.i(message)
}

In app module create TimberLogger.kt:

import timber.log.Timber

class TimberLogger : ILogger {

    override fun d(message: String) = Timber.d(message) // this is real timber this time
    override fun e(message: String) = Timber.e(message)
    override fun e(throwable: Throwable, message: String) = Timber.e(throwable, message)
    override fun i(message: String) = Timber.i(message)
}

In app module, inject TimberLogger implementation into your fake Timber:

val appModule = module {

    single<ILogger> { TimberLogger() }
}

Now you can simply call Timber.d("message") statically from anywhere.

If you have 2+ pure modules to use Timber in, consider creating Utils module and include it in rest of them, so it's available everywhere.

solidogen
  • 591
  • 5
  • 12
  • A little more functionality, and you don't need Timber at all – Leo DroidCoder Feb 17 '21 at 15:44
  • This works well, except it stops the automatic tag inference algorithm in `DebugTree` from working. The automatic tag now is "TimberLogger" because `DebugTree` inspects the call stack, which is altered if `Timber` calls are wrapped. – Peter F Jun 16 '21 at 15:12
  • 1
    @PeterF you need to fetch correct tag from stacktrace. You can do this by extending DebugTree like here: https://github.com/chrisbanes/tivi/blob/main/base-android/src/main/java/app/tivi/util/TiviLogger.kt – solidogen Jun 16 '21 at 15:34
1

Try Arbor: Timber like logging implementation for Kotlin Multiplatform.

https://github.com/ToxicBakery/Arbor

drakeet
  • 2,685
  • 1
  • 23
  • 30