Skip to content

Commit

Permalink
clickable log source added
Browse files Browse the repository at this point in the history
  • Loading branch information
Noddy20 committed Jul 1, 2022
1 parent 9954d94 commit bac08b6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 12 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The `DebugTree` implementation will automatically figure out from which class it
use that class name as its tag. Since the tags vary, it works really well when coupled with a log
reader like [Pidcat][1].

The `DebugTree` implementation also supports clickable logs in logcat. It will provide a clickable
location in format (FILENAME:LINE_NUMBER). You can disable it by passing `clickableSourceEnabled`
false in `DebugTree` constructor.

There are no `Tree` implementations installed by default because every time you log in production, a
puppy dies.

Expand Down
46 changes: 34 additions & 12 deletions timber/src/main/java/timber/log/Timber.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class Timber private constructor() {
return tag
}

@get:JvmSynthetic // Hide from public API.
internal open val source: String? = null

/** Log a verbose message with optional format args. */
open fun v(message: String?, vararg args: Any?) {
prepareLog(Log.VERBOSE, null, message, *args)
Expand Down Expand Up @@ -193,26 +196,31 @@ class Timber private constructor() {
}

/** A [Tree] for debug builds. Automatically infers the tag from the calling class. */
open class DebugTree : Tree() {
open class DebugTree(private val clickableSourceEnabled: Boolean = true) : Tree() {
private val fqcnIgnore = listOf(
Timber::class.java.name,
Timber.Forest::class.java.name,
Tree::class.java.name,
DebugTree::class.java.name
Timber::class.java.name,
Timber.Forest::class.java.name,
Tree::class.java.name,
DebugTree::class.java.name
)

override val tag: String?
get() = super.tag ?: Throwable().stackTrace
.first { it.className !in fqcnIgnore }
.let(::createStackElementTag)
.first { it.className !in fqcnIgnore }
.let(::createStackElementTag)

override val source: String?
get() = Throwable().stackTrace
.first { it.className !in fqcnIgnore }
.let(::createStackElementSource)

/**
* Extract the tag which should be used for the message from the `element`. By default
* this will use the class name without any anonymous class suffixes (e.g., `Foo$1`
* becomes `Foo`).
*
* Note: This will not be called if a [manual tag][.tag] was specified.
*/
*/
protected open fun createStackElementTag(element: StackTraceElement): String? {
var tag = element.className.substringAfterLast('.')
val m = ANONYMOUS_CLASS.matcher(tag)
Expand All @@ -227,14 +235,28 @@ class Timber private constructor() {
}
}

/**
* Extract the source (File Name & Line Number)
*/
protected open fun createStackElementSource(element: StackTraceElement): String? {
return with(element){
"($fileName:$lineNumber)"
}
}

/**
* Break up `message` into maximum-length chunks (if needed) and send to either
* [Log.println()][Log.println] or
* [Log.wtf()][Log.wtf] for logging.
*
* {@inheritDoc}
*/
*/
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
val message = if (clickableSourceEnabled) {
"$source $message"
} else {
message
}
if (message.length < MAX_LOG_LENGTH) {
if (priority == Log.ASSERT) {
Log.wtf(tag, message)
Expand Down Expand Up @@ -385,10 +407,10 @@ class Timber private constructor() {
/**
* A view into Timber's planted trees as a tree itself. This can be used for injecting a logger
* instance rather than using static methods or to facilitate testing.
*/
*/
@Suppress(
"NOTHING_TO_INLINE", // Kotlin users should reference `Tree.Forest` directly.
"NON_FINAL_MEMBER_IN_OBJECT" // For japicmp check.
"NOTHING_TO_INLINE", // Kotlin users should reference `Tree.Forest` directly.
"NON_FINAL_MEMBER_IN_OBJECT" // For japicmp check.
)
@JvmStatic
open inline fun asTree(): Tree = this
Expand Down

0 comments on commit bac08b6

Please sign in to comment.