How to insert a log in LogCat that when I click on it jumps to its line in code?
I found it:
public static void showLogCat(String tag, String msg) {
StackTraceElement[] stackTraceElement = Thread.currentThread()
.getStackTrace();
int currentIndex = -1;
for (int i = 0; i < stackTraceElement.length; i++) {
if (stackTraceElement[i].getMethodName().compareTo("showLogCat") == 0)
{
currentIndex = i + 1;
break;
}
}
String fullClassName = stackTraceElement[currentIndex].getClassName();
String className = fullClassName.substring(fullClassName
.lastIndexOf(".") + 1);
String methodName = stackTraceElement[currentIndex].getMethodName();
String lineNumber = String
.valueOf(stackTraceElement[currentIndex].getLineNumber());
Log.i(tag, msg);
Log.i(tag + " position", "at " + fullClassName + "." + methodName + "("
+ className + ".java:" + lineNumber + ")");
}
Its usage:
showLogCat("tag", "message");
The important thing is to insert "(X:Y)"
in your log message, while X
is your desired file name and Y
is your desired line number in X
. (I learned it from @breceivemail's answer). So try:
public static void log(final String tag, final String msg) {
final StackTraceElement stackTrace = new Exception().getStackTrace()[1];
String fileName = stackTrace.getFileName();
if (fileName == null) fileName=""; // It is necessary if you want to use proguard obfuscation.
final String info = stackTrace.getMethodName() + " (" + fileName + ":"
+ stackTrace.getLineNumber() + ")";
Log.LEVEL(tag, info + ": " + msg);
}
Note: The LEVEL
is the log level and can be v
, d
, i
, w
, e
or wtf
.
Now you can use log(tag, msg)
instead of Log.LEVEL(tag, msg)
.
Example:
MainActivity.java:
...
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
log("Test Tag", "Hello World!");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
...
The output:
12-30 14:24:45.343 ? I/Test Tag: onCreate (MainActivity.java:10): Hello World!
And MainActivity.java:10
automatically would be a link and you can click on it!
You can also assign following value to info
variable if you want more verbose log:
final String info = stackTrace.getClassName() + "." + stackTrace.getMethodName() + " ("
+ fileName + ":" + stackTrace.getLineNumber() + ")\n";
So the output of above example would be:
12-30 14:33:07.360 ? I/Test Tag: com.example.myapp.MainActivity.onCreate (MainActivity.java:11)
Hello World!
Please use this Tree with Timber.
class MyLinkingTimberTree : Timber.DebugTree() {
override fun createStackElementTag(element: StackTraceElement): String? {
return makeClickableLineNumber(element)
}
private fun makeClickableLineNumber(
element: StackTraceElement
): String {
val className = element.fileName
val methodName = element.methodName
val lineNumber = element.lineNumber
val fileName = element.fileName
val stringBuilder = StringBuilder(className)
.append(".")
.append(methodName)
.append(" (")
.append(fileName)
.append(":")
.append(lineNumber)
.append(") ")
return stringBuilder.toString()
}
}
And then just instantiate it like this:
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
if(BuildConfig.DEBUG) {
Timber.plant(MyLinkingTimberTree())
}
}
}
Then just use Timber normally:
Timber.d("Currently Signed in:")
And this is the result. Nice, isn't it? I hope you enjoy using it as much as I enjoyed making it! ;)