JakeWharton / timber

A logger with a small, extensible API which provides utility on top of Android's normal Log class.
https://jakewharton.github.io/timber/docs/5.x/
Apache License 2.0
10.46k stars 962 forks source link

Added the HyperlinkedDebugTree class that creates Logs that include hyperlinks to the calling line #377

Open Merthan opened 4 years ago

Merthan commented 4 years ago

Added the HyperlinkedDebugTree class that creates Logs that include hyperlinks to the calling line

This way you can just click on the Tag and directly jump to the source. Very useful in big projects.

I think this should be included in some form as otherwise people who use the library won't know that this is even a possibility. I certainly didn't :D The class also has a boolean variable that controls whether or not to show the method name too.

So planting it either looks like this: Timber.plant(HyperlinkedDebugTree(false)) Or (because it's default value is true): Timber.plant(HyperlinkedDebugTree())

This then looks similar to this (with clickable Hyperlinks) D/(AddItemFragment.kt:222)getImageCaptureUri(): logMessage

D/(AddItemFragment.kt:222): logMessage (there is no space before the ":", only here because I had to mark it as a link)

If you want to merge this PR but I forgot something like Testing or perhaps stuff like adding it in the Changelog, tell me.

At some point this might even be useful in the Readme file🗡

elfifo4 commented 1 year ago

@Merthan, in new versions of Android Studio, your idea should be implemented a bit differently:

/**
 * A [Tree] for debug builds.
 * Automatically shows a Hyperlink to the calling Class and LineNumber in the Logs.
 * Allows quick lookup of the caller source just by clicking on the Hyperlink in the Log.
 * @param showMethodName Whether or not to show the method name as well
 */
class HyperlinkedDebugTree(private val showMethodName: Boolean = true) : Timber.DebugTree() {

    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        super.log(priority, tag, getHyperlink() + message, t)
    }

    private fun getHyperlink(): String =
        Thread.currentThread().stackTrace.let { elements: Array<StackTraceElement> ->
            val index = 7 // most relevant StackTraceElement index that actually prints to logcat
            elements[index].let {
                "(${it.fileName}:${it.lineNumber}) "
            }
        }

}
mirokolodii commented 1 month ago

Alternatively, to not rely on StackTraceElement's index, tag with hyperlink can be put directly in message:

    override fun createStackElementTag(element: StackTraceElement) =
        with(element) { "($fileName:$lineNumber) ${if (showMethodName) " $methodName()" else ""}" }

    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        val newMessage = listOfNotNull(
            tag,
            message,
        ).joinToString(separator = " ")

        super.log(priority = priority, tag = tag, message = newMessage, t = t)
    }
}