From 292bece71d8380feb2da8ca9ca4a2dfd9b82524c Mon Sep 17 00:00:00 2001 From: mflisar Date: Thu, 22 Oct 2020 08:50:04 +0200 Subject: [PATCH] code clean up --- .../lumberjack/demo/MainActivity.kt | 16 +-- .../java/com/michaelflisar/lumberjack/L.kt | 8 +- .../lumberjack/data/StackData.kt | 110 ++++++++++++++---- library/src/main/java/timber/log/BaseTree.kt | 6 +- .../src/main/java/timber/log/ConsoleTree.kt | 4 +- 5 files changed, 106 insertions(+), 38 deletions(-) diff --git a/demo/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt b/demo/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt index 5923d8c..4bf526d 100644 --- a/demo/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt +++ b/demo/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt @@ -14,7 +14,7 @@ class MainActivity : AppCompatActivity() { L.d { "1 - MainActivity onCreate was just called" } L.logIf { false }?.d { - // sleep 60s - no problem, this block will never be executed + // sleep 60s - no problem, this block will never be executed thanks to lazy evaluation Thread.sleep(1000 * 60) "2 - this log will never be printed nor will this block ever be executed" } @@ -25,16 +25,16 @@ class MainActivity : AppCompatActivity() { // Specials // -------------- - val func = { - L.d { "5 - from within lambda" } - // 2 steps up, one for func and one for the func invoke => the link in the console logger won't work because the caller line is the function call... but it points to the correct line - L.callStackCorrection(2) - .d { "6 - from within lambda and forcefully telling Lumberjack that we want to log the func callers line" } + val func = { info: String -> + L.d { "5 - from within lambda: $info" } } - func() + + func("func call 1...") + func("func call 2...") + func("func call 3...") lifecycle.coroutineScope.launch(Dispatchers.IO) { - L.d { "7 - from within coroutine on background thread: ${Thread.currentThread()}" } + L.d { "6 - from within coroutine on background thread: ${Thread.currentThread()}" } } } diff --git a/library/src/main/java/com/michaelflisar/lumberjack/L.kt b/library/src/main/java/com/michaelflisar/lumberjack/L.kt index 0ef5d29..64a398b 100644 --- a/library/src/main/java/com/michaelflisar/lumberjack/L.kt +++ b/library/src/main/java/com/michaelflisar/lumberjack/L.kt @@ -30,6 +30,12 @@ object L { */ var tagNameFilter: ((tags: String) -> Boolean)? = null + /* + * if enabled, Lumberjack will try to log find out a lambdas caller and append this info to the log tag + * does not work perfectly, we would to distinguish between lambdas called directly or by a coroutine and more... + */ + internal val advancedLambdaLogging = false + // -------------- // special functions // -------------- @@ -112,7 +118,7 @@ object L { @PublishedApi internal inline fun log(t: Throwable?, logBlock: () -> Unit) { if (enabled && Timber.treeCount() > 0) { - if (packageNameFilter?.let { it.invoke(StackData.create(t, 0).className) } != false) + if (packageNameFilter?.let { it.invoke(StackData(t, 0).getCallingPackageName()) } != false) logBlock() } } diff --git a/library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt b/library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt index 5456af2..788d5d3 100644 --- a/library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt +++ b/library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt @@ -1,37 +1,99 @@ package com.michaelflisar.lumberjack.data +import com.michaelflisar.lumberjack.L import java.util.regex.Pattern - -class StackData( - val className: String, - val simpleFileName: String, - val methodName: String, - val line: Int -) { +class StackData { companion object { private val ANONYMOUS_CLASS = Pattern.compile("(\\$\\d+)+$") + } - fun create(t: Throwable?, callStackIndex: Int): StackData { - val stackTrace = t?.stackTrace ?: Throwable().stackTrace - val index = if (t != null) 0 else (callStackIndex + 1) - if (stackTrace.size <= index) { - throw IllegalStateException( - "Synthetic stacktrace didn't have enough elements: are you using proguard?" - ) - } - val element = stackTrace[index] - var tag = element.className - val m = ANONYMOUS_CLASS.matcher(tag) - if (m.find()) { - tag = m.replaceAll("") + lateinit var element: StackTraceElement + private set + var element2: StackTraceElement? = null + private set + + val className by lazy { + getClassName(element) + } + + val className2 by lazy { + getClassName(element2) + } + + constructor(t: Throwable?, callStackIndex: Int) { + + val stackTrace = t?.stackTrace ?: Throwable().stackTrace + val index = if (t != null) 0 else (callStackIndex + 1) + + element = getElement(stackTrace, index) + if (L.advancedLambdaLogging) { + // functions can not start with numbers, so of the class name ends with a number, this must be a lambda which is handled as anonymous function + val split = element.className.split("$") + if (split.lastOrNull()?.toIntOrNull() != null) { + // example from demo: + // com.michaelflisar.lumberjack.demo.MainActivity$onCreate$func$1 + // => so we need to go up +2, because we want to get the line in onCreate where the caller executes the lambda + element2 = element + element = getElement(stackTrace, index + 2) } - return StackData(tag, element.fileName, element.methodName, element.lineNumber) } } - val simpleClassName: String = className.substring(className.lastIndexOf('.') + 1) - val stackTag = "$simpleClassName:$line $methodName" - val link = "$simpleFileName:$line" + // ------------------------ + // functions + // ------------------------ + + fun getStackTag(): String { + val simpleClassName = getSimpleClassName(className) + var tag = "$simpleClassName:${element.lineNumber} ${element.methodName}" + element2?.let { + val simpleClassName2 = getSimpleClassName(className2) + val extra = simpleClassName2.replace(simpleClassName, "") + tag += " ($extra:${it.lineNumber})" + } + return tag + } + + fun getLink(): String { + var link = "(${element.fileName}:${element.lineNumber})" + // AndroidStudio does not support 2 clickable links... + element2?.let { + link += " | (${it.fileName}:${it.lineNumber})" + } + return link + } + + fun getCallingPackageName(): String { + return className + } + + // ------------------------ + // private helper functions + // ------------------------ + + private fun getElement(stackTrace: Array, index: Int): StackTraceElement { + if (stackTrace.size <= index) { + throw IllegalStateException( + "Synthetic stacktrace didn't have enough elements: are you using proguard?" + ) + } + return stackTrace[index] + } + + private fun getClassName(element: StackTraceElement?): String { + if (element == null) + return "" + var tag = element.className + val m = ANONYMOUS_CLASS.matcher(tag) + if (m.find()) { + tag = m.replaceAll("") + } + return tag + } + + private fun getSimpleClassName(className: String): String { + return className.substring(className.lastIndexOf('.') + 1) + } } \ No newline at end of file diff --git a/library/src/main/java/timber/log/BaseTree.kt b/library/src/main/java/timber/log/BaseTree.kt index 58ab0d9..41e3229 100644 --- a/library/src/main/java/timber/log/BaseTree.kt +++ b/library/src/main/java/timber/log/BaseTree.kt @@ -168,7 +168,7 @@ abstract class BaseTree : Timber.Tree() { // custom: we create a stack data object val callStackCorrection = getCallStackCorrection() ?: 0 - val stackData = StackData.create(t, CALL_STACK_INDEX + callStackCorrection) + val stackData = StackData(t, CALL_STACK_INDEX + callStackCorrection) // Consume tag even when message is not loggable so that next message is correctly tagged. @Suppress("NAME_SHADOWING") var message = message @@ -228,9 +228,9 @@ abstract class BaseTree : Timber.Tree() { // 2) create a custom tag for the logs return if (customTag != null) { - "[<$customTag> ${stackData.stackTag}]" + "[<$customTag> ${stackData.getStackTag()}]" } else { - "[${stackData.stackTag}]" + "[${stackData.getStackTag()}]" } } diff --git a/library/src/main/java/timber/log/ConsoleTree.kt b/library/src/main/java/timber/log/ConsoleTree.kt index fc7875b..71655e6 100644 --- a/library/src/main/java/timber/log/ConsoleTree.kt +++ b/library/src/main/java/timber/log/ConsoleTree.kt @@ -61,7 +61,7 @@ class ConsoleTree( } private fun appendLink(message: String, stackData: StackData): String { - val link = stackData.link - return "$message ($link)" + val link = stackData.getLink() + return "$message $link" } } \ No newline at end of file