'Log method name and line number in Timber

Is possible log the current line number and method name using the Timber library?

Expected LogCat result:

ismaeldivita.myapp I/[L:22] [M:onResume] [C:HomeActivity]: Praise the log!


Solution 1:[1]

Answering my own question.

Just create a new DebugTree class

public class MyDebugTree extends Timber.DebugTree {    
    @Override
    protected String createStackElementTag(StackTraceElement element) {
        return String.format("[L:%s] [M:%s] [C:%s]",
                element.getLineNumber(),
                element.getMethodName(),
                super.createStackElementTag(element));
    }
}

And plant your Tree in Timber:

public class App extends Application {
    @Override
    public void onCreate(){
        super.onCreate();
        if (BuildConfig.DEBUG) {
           Timber.plant(new MyDebugTree());
        } else {
           //TODO plant your Production Tree
        }
    }
}

Solution 2:[2]

improving on Ismael Di Vita answer so it displays in logcat as a hyperlink like this.

public class MyDebugTree extends Timber.DebugTree {     
    @Override 
    protected String createStackElementTag(StackTraceElement element) {
        return String.format("(%s:%s)#%s",
            element.getFileName(),
            element.getLineNumber(),
            element.getMethodName());
    } 
} 

or for kotlin

class LineNumberDebugTree : Timber.DebugTree() {
override fun createStackElementTag(element: StackTraceElement): String? {
    return "(${element.fileName}:${element.lineNumber})#${element.methodName}"
}

}

Note: use element.fileName instead of element.className so it works in kotlin for logging outside a class

from my utils lib

Solution 3:[3]

That is how i solved it in my Application class using Kotlin:

class App : Application() {

override fun onCreate() {
    super.onCreate()
    initLogger()
}

private fun initLogger() {
    if (BuildConfig.DEBUG) {
        Timber.plant(object : Timber.DebugTree() {
            override fun createStackElementTag(element: StackTraceElement): String? {
                return "(${element.fileName}:${element.lineNumber})#${element.methodName}"
            }
        })
    }
}

Solution 4:[4]

I use this class.

object Logg {
  private fun tag(): String? {
    return Thread.currentThread().stackTrace[4].let {
      val link = "(${it.fileName}:${it.lineNumber})"
      val path = "App# ${it.className.substringAfterLast(".")}.${it.methodName}"
      if (path.length + link.length > 80) {
        "${path.take(80 - link.length)}...${link}"
      } else {
        "$path$link"
      }
    }
  }

  fun v(msg: String?) {
    Log.v(tag(), "? $msg")
  }

  fun d(msg: String?) {
    Log.d(tag(), "? $msg")
  }

  fun i(msg: String?) {
    Log.i(tag(), "? $msg")
  }

  fun w(msg: String?) {
    Log.w(tag(), "? $msg")
  }

  fun w(e: Throwable?) {
    Log.w(tag(), "? ${e?.localizedMessage}")
    e?.printStackTrace()
  }

  fun w(e: Exception?) {
    Log.w(tag(), "? ${e?.localizedMessage}")
    e?.printStackTrace()
  }
  
  fun w(e: LinkageError?) {
    Log.w(tag(), "? ${e?.localizedMessage}")
    e?.printStackTrace()
  }

  fun e(msg: String?) {
    Log.e(tag(), "? $msg")
  }

  fun e(e: Throwable?) {
    Log.e(tag(), "? ${e?.localizedMessage}")
    e?.printStackTrace()
  }

  fun e(e: java.lang.Exception?) {
    Log.e(tag(), "? ${e?.localizedMessage}")
    e?.printStackTrace()
  }
}

How to use:

Logg.e("====== log here ==========")

Result:

enter image description here

Solution 5:[5]

Extending on Ugurcan Yildirim answer so it handles lambda method names as well

            @Override
            protected String createStackElementTag(@NonNull StackTraceElement element) {
                String mName=element.getMethodName();
                if(mName.startsWith("lambda$")){
                    String[] frames = mName.split("\\$");
                    if(frames.length>2){
                        mName = frames[0] + "$"+ frames[1];
                    }
                }
                String x = String.format("(%s:%s)#%s",element.getFileName(),element.getLineNumber(),mName);
                return x;
            }

Without above fix for logs where methodName returns e.g. lambda$onCreate$8$com-swiftthoughts-wordkons-ActivityStartJoinGame the debug log appears on log cat as

[          1651187461.198  6333: 6333 D/(ActivityStartJoinGame.java:264)#lambda$onCreate$8$com-swiftthoughts-wordkons-ALog out clicked

With above changes it appears as expected

2022-04-29 04:58:37.514 6925-6925/com.swiftthoughts.wordkons D/ajdebug-(ActivityStartJoinGame.java:264)#lambda$onCreate: Log out clicked

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ugurcan Yildirim
Solution 3 Roman
Solution 4
Solution 5 Amit