Android Remote Logging via Timber and Firestore (Kotlin)

July 8, 2019

I wanted to perform remote Android logging for specific users and conditions for release debugging purpose.



By default, Timber support custom output handlers. Firestore is the easiest method to send data to remote server without the need to write a RESTful API, and there is a simple console UI to view the data.

Remote logging handler for Timber. Only log for


  • Use user_log collection with user id as document id. (allow me to debug log messages by user easily)
  • Using single document to store all log messages per user, storing them in map using Timestamp as the key.
  • Using updateOrCreate to make sure partial update is successful even when document does not exist.
  • Since firestore map key must be String, I am using and convert it to device local timezone datetime string. I could use UTC as well.
// class RemoteLoggingTree: Timber.DebugTree() {
class RemoteLoggingTree: Timber.Tree() {
    private val watchUids = listOf(
        "QYHqCKCGSbY3qqMSliqNhR3j9QD2", // Desmond
        "CHqMRFyD6OeavAIz1xKx2yLEM3Z2", // Mei Ru
        "iDCeXV2lFCSNBKx94euaTczicyp1"  // JackJack

    private val watchTags = listOf(

    override fun isLoggable(tag: String?, priority: Int): Boolean {
        return priority >= Log.INFO

    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        if (priority == Log.VERBOSE || priority == Log.DEBUG) {

        val user = FirebaseAuth.getInstance().currentUser
        // tag is null unless .tag() is called
        // override Timber.DebugTree will have performance penalty

        if (user != null && watchUids.contains(user.uid) && watchTags.contains(tag)) {
            val db = FirebaseFirestore.getInstance()

            val ref = db.collection("user_log").document(user.uid)

            val priorityString = when(priority) {
                Log.INFO -> "I"
                Log.WARN -> "W"
                Log.ERROR -> "E"
                else -> ""

            // Log.i("RemoteLoggingTree", "log to firestore")
            val logString = "$priorityString/$tag: $message"
            // firestore map key must be String - use device local timestamp
            val key =
                "logs" to mapOf(
                    key to logString
        else {
            // Log.i("RemoteLoggingTree", "skip log -> $message")
            // super.log(priority, tag, message, t)

Enable remote logging for RELEASE only.

class LuaApp: Application() {
    override fun onCreate() {
        if (BuildConfig.DEBUG) {
        } else {


val TAG =  "ReminderWorker"

Timber.tag(TAG).i("doWork: show notification")

// e = Exception

View logs from Firebase Database Console.

Firebase Database Console

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.