Android Better Logging using Timber Library

Timber is a powerful logging tool built on Android’s Log class, making logging simpler and more efficient. It allows automatic filtering of log statements by build type, removing the need for tedious manual cleanup before release.

Timber offers many useful features for better logging. Let’s see how we can use it in our projects to keep logs organized.

1. Timber

Below are the few debug statements that are printed using default Log class.

val a = 100
Log.e("TAG", String.format("Integer a value is: %d", a))

val name = "Android Studio"
Log.e("TAG", String.format("My name is: %s", name))
    
The same statements can be printed using Timber as below.

// integer
val a = 100
Timber.d("Integer a value is: %d", a)

val name = "Android Studio"
Timber.d("My name is: %s", name)
    
  • You can notice here, the TAG is not passed to Timber as it automatically detects the class in which logs were written.
  • Also, the String formatter is not used to format the statement as Timber can do it automatically for you.

2. Integrating Timber

Now let's see how to integrate the library in your project making it available in every class.
  1. Create a new project in Android Studio from File ⇒ New Project and select Empty Activities from templates.
  2. Open build.gradle and add Timber dependency.
    
    implementation 'com.jakewharton.timber:timber:5.0.1'
        
  3. Timber has to be initialized as soon as app starts. So, Application class would be best place to do that. Create new class named MyApplication.kt and extend the class from Application.
    1. Initialize Timber in onCreate method by planting a new Tree.
    2. Use Timber.DebugTree() to print the logs only in debug mode.
    3. If you want to catch exceptions in release mode, you can create a different Tree and plant it in release mode. This step is completely optional but if you want to send exceptions to a different service, this is the appropriate place to do it.
    MyApplication.kt
    
    package info.androidhive.android_timber
    
    import android.app.Application
    import android.util.Log
    import timber.log.Timber
    
    
    class MyApplication : Application() {
        override fun onCreate() {
            super.onCreate()
    
            if (BuildConfig.DEBUG) {
                Timber.plant(Timber.DebugTree())
            } else {
                Timber.plant(ReleaseTree())
            }
        }
    
        private class ReleaseTree : Timber.Tree() {
            override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
                if (priority == Log.VERBOSE || priority == Log.DEBUG) {
                    return
                }
    
                // log your crash to your favourite
                // Sending crash report to Firebase CrashAnalytics
    
                // FirebaseCrash.report(message);
                // FirebaseCrash.report(new Exception(message));
            }
        }
    }
        
  4. Don't forget to add MyApplication to your <application> tag in your AndroidManifest.xml
    MyApplication.kt
    
    <application
            ....
            android:name=".MyApplication"
        
  5. Now, Timber is ready to be used in your app. Below are the few examples of Timber log statements demonstrating different scenarios.
    
    package info.androidhive.android_timber
    
    import android.os.Bundle
    import androidx.activity.enableEdgeToEdge
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.view.ViewCompat
    import androidx.core.view.WindowInsetsCompat
    import timber.log.Timber
    
    
    @Suppress("DIVISION_BY_ZERO")
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            enableEdgeToEdge()
            setContentView(R.layout.activity_main)
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
                val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
                insets
            }
    
            Timber.d("Hello from Timber!")
    
            // boolean
            val isWeekend = false
            Timber.d("This prints the boolean value. Is weekend: %b", isWeekend)
    
            // integer
            val a = 100
            Timber.d("Integer a value is: %d", a)
    
            // float
            val pi = 3.14159f
            Timber.d("Pi value is: %f", pi)
    
            try {
                val ans = 10 / 0
                Timber.d("Value of a: %d", ans)
            } catch (e: Exception) {
                Timber.e(e)
    
                // or
                Timber.e("Exception in math operation: %s", e.message)
            }
        }
    }
        
Let me know your queries in the comments section below.

Cheers!
Happy Coding 🤗
Previous Post Next Post

نموذج الاتصال