From b462b48be1b2d0418cd4563a42d824861a8cb7b4 Mon Sep 17 00:00:00 2001 From: MichaelFlisar Date: Fri, 18 Jan 2019 10:31:28 +0100 Subject: [PATCH] own class for java logging --- .../lumberjack/demo/JavaTest.java | 13 +- .../lumberjack/demo/MainActivity.kt | 3 +- .../java/com/michaelflisar/lumberjack/L.kt | 95 ------------- .../java/com/michaelflisar/lumberjack/L2.kt | 125 ++++++++++++++++++ .../lumberjack/data/StackData.kt | 13 -- library/src/main/java/timber/log/BaseTree.kt | 28 +++- .../src/main/java/timber/log/ConsoleTree.kt | 3 +- 7 files changed, 158 insertions(+), 122 deletions(-) create mode 100644 library/src/main/java/com/michaelflisar/lumberjack/L2.kt diff --git a/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/JavaTest.java b/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/JavaTest.java index 81f8809..521de80 100644 --- a/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/JavaTest.java +++ b/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/JavaTest.java @@ -1,17 +1,18 @@ package com.michaelflisar.lumberjack.demo; -import com.michaelflisar.lumberjack.L; +import com.michaelflisar.lumberjack.L2; public class JavaTest { public static void test() { - L.d(new Throwable()); + // USE L2 in JAVA code, otherwise callstack won't be correct because of missing inlining functionality in java! + L2.d(new Throwable(), "JAVA 1 - ERROR"); - L.d("JAVA 1 - Test message"); - L.d("JAVA 2 - Test message with arg: %d", 500); - L.e(new Throwable("ERROR"), "JAVA 3 - Test error"); + L2.d("JAVA 2 - Test message"); + L2.d("JAVA 3 - Test message with arg: %d", 500); + L2.e(new Throwable("ERROR"), "JAVA 4 - Test error"); - L.tag("CUSTOM-TAG").d("JAVA 4 - Test message with custom tag"); + L2.tag("CUSTOM-TAG").d("JAVA 5 - Test message with custom tag"); } } diff --git a/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt b/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt index ee517b7..5e88c44 100644 --- a/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt +++ b/demo/app/src/main/java/com/michaelflisar/lumberjack/demo/MainActivity.kt @@ -24,8 +24,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener { // Test 1: a few simple test messages L.d { "1 - Main activity created" } - L.d { "2a - Test message - count: $count" } // kotlin style args - L.d("2b - Test message - count: %d", count) // java style args - non lazy!!! + L.d { "2 - Test message - count: $count" } L.e(Throwable("ERROR"), { "3 - Test error" }) L.tag("CUSTOM-TAG").d { "4 - Test message with custom tag" } diff --git a/library/src/main/java/com/michaelflisar/lumberjack/L.kt b/library/src/main/java/com/michaelflisar/lumberjack/L.kt index 903968f..c2d4674 100644 --- a/library/src/main/java/com/michaelflisar/lumberjack/L.kt +++ b/library/src/main/java/com/michaelflisar/lumberjack/L.kt @@ -27,7 +27,6 @@ object L { } } - @JvmStatic fun tag(tag: String): L { Timber.tag(tag) return L @@ -37,147 +36,53 @@ object L { // log functions - lazy // -------------- - @JvmStatic inline fun v(t: Throwable? = null, message: () -> String) = log { Timber.v(t, message()) } - @JvmStatic inline fun v(t: Throwable?) = log { Timber.v(t) } - @JvmStatic inline fun v(message: () -> String) = log { Timber.v(message()) } - @JvmStatic inline fun d(t: Throwable? = null, message: () -> String) = log { Timber.d(t, message()) } - @JvmStatic inline fun d(t: Throwable?) = log { Timber.d(t) } - @JvmStatic inline fun d(message: () -> String) = log { Timber.d(message()) } - @JvmStatic inline fun i(t: Throwable? = null, message: () -> String) = log { Timber.i(t, message()) } - @JvmStatic inline fun i(t: Throwable?) = log { Timber.i(t) } - @JvmStatic inline fun i(message: () -> String) = log { Timber.i(message()) } - @JvmStatic inline fun w(t: Throwable? = null, message: () -> String) = log { Timber.w(t, message()) } - @JvmStatic inline fun w(t: Throwable?) = log { Timber.w(t) } - @JvmStatic inline fun w(message: () -> String) = log { Timber.w(message()) } - @JvmStatic inline fun e(t: Throwable? = null, message: () -> String) = log { Timber.e(t, message()) } - @JvmStatic inline fun e(t: Throwable?) = log { Timber.e(t) } - @JvmStatic inline fun e(message: () -> String) = log { Timber.e(message()) } - @JvmStatic inline fun wtf(t: Throwable? = null, message: () -> String) = log { Timber.wtf(t, message()) } - @JvmStatic inline fun wtf(t: Throwable?) = log { Timber.wtf(t) } - @JvmStatic inline fun wtf(message: () -> String) = log { Timber.wtf(message()) } - // -------------- - // log functions - NON lazy for usage in java code (backwards compatibility, usage with java libraries) - // -------------- - - @JvmStatic - inline fun v(t: Throwable? = null, message: String, vararg args: Any) = log { Timber.v(t, message, args) } - - @JvmStatic - inline fun v(message: String, vararg args: Any) = log { Timber.v(message, args) } - - @JvmStatic - inline fun v(message: String) = log { Timber.v(message) } - - @JvmStatic - inline fun d(t: Throwable? = null, message: String, vararg args: Any) = log { Timber.d(t, message, args) } - - @JvmStatic - inline fun d(t: Throwable? = null, message: String) = log { Timber.d(t, message) } - - @JvmStatic - inline fun d(message: String, vararg args: Any) = log { Timber.d(message, args) } - - @JvmStatic - inline fun d(message: String) = log { Timber.d(message) } - - @JvmStatic - inline fun i(t: Throwable? = null, message: String, vararg args: Any) = log { Timber.i(t, message, args) } - - @JvmStatic - inline fun i(t: Throwable? = null, message: String) = log { Timber.i(t, message) } - - @JvmStatic - inline fun i(message: String, vararg args: Any) = log { Timber.i(message, args) } - - @JvmStatic - inline fun i(message: String) = log { Timber.i(message) } - - @JvmStatic - inline fun w(t: Throwable? = null, message: String, vararg args: Any) = log { Timber.w(t, message, args) } - - @JvmStatic - inline fun w(t: Throwable? = null, message: String) = log { Timber.w(t, message) } - - @JvmStatic - inline fun w(message: String, vararg args: Any) = log { Timber.w(message, args) } - - @JvmStatic - inline fun w(message: String) = log { Timber.w(message) } - - @JvmStatic - inline fun e(t: Throwable? = null, message: String, vararg args: Any) = log { Timber.e(t, message, args) } - - @JvmStatic - inline fun e(t: Throwable? = null, message: String) = log { Timber.e(t, message) } - - @JvmStatic - inline fun e(message: String, vararg args: Any) = log { Timber.e(message, args) } - - @JvmStatic - inline fun e(message: String) = log { Timber.e(message) } - - @JvmStatic - inline fun wtf(t: Throwable? = null, message: String, vararg args: Any) = log { Timber.wtf(t, message, args) } - - @JvmStatic - inline fun wtf(t: Throwable? = null, message: String) = log { Timber.wtf(t, message) } - - @JvmStatic - inline fun wtf(message: String, vararg args: Any) = log { Timber.wtf(message, args) } - - @JvmStatic - inline fun wtf(message: String) = log { Timber.wtf(message) } // -------------- // timber forward functions // -------------- - @JvmStatic inline fun asTree(): Timber.Tree = Timber.asTree() - @JvmStatic inline fun plant(tree: Timber.Tree) = Timber.plant(tree) - @JvmStatic inline fun uproot(tree: Timber.Tree) = Timber.uproot(tree) - @JvmStatic inline fun uprootAll() = Timber.uprootAll() // -------------- diff --git a/library/src/main/java/com/michaelflisar/lumberjack/L2.kt b/library/src/main/java/com/michaelflisar/lumberjack/L2.kt new file mode 100644 index 0000000..dd2d1ed --- /dev/null +++ b/library/src/main/java/com/michaelflisar/lumberjack/L2.kt @@ -0,0 +1,125 @@ +package com.michaelflisar.lumberjack + +import timber.log.BaseTree +import timber.log.Timber + +/* + this class is meant for usage in JAVA only, as functions can't be inlined there + and the callstack index to find the interesting callers class is different because of not inlining the functions! + */ +object L2 { + + @JvmStatic + fun tag(tag: String): L2 { + Timber.tag(tag) + return L2 + } + + @JvmStatic + fun v(t: Throwable?) = L2.log { Timber.v(t) } + + @JvmStatic + fun v(t: Throwable? = null, message: String, vararg args: Any) = L2.log { Timber.v(t, message, *args) } + + @JvmStatic + fun v(message: String, vararg args: Any) = L2.log { Timber.v(message, *args) } + + @JvmStatic + fun v(message: String) = L2.log { Timber.v(message) } + + @JvmStatic + fun d(t: Throwable?) = L2.log { Timber.d(t) } + + @JvmStatic + fun d(t: Throwable? = null, message: String, vararg args: Any) = L2.log { Timber.d(t, message, *args) } + + @JvmStatic + fun d(t: Throwable? = null, message: String) = L2.log { Timber.d(t, message) } + + @JvmStatic + fun d(message: String, vararg args: Any) = L2.log { Timber.d(message, *args) } + + @JvmStatic + fun d(message: String) = L2.log { Timber.d(message) } + + @JvmStatic + fun i(t: Throwable?) = L2.log { Timber.i(t) } + + @JvmStatic + fun i(t: Throwable? = null, message: String, vararg args: Any) = L2.log { Timber.i(t, message, *args) } + + @JvmStatic + fun i(t: Throwable? = null, message: String) = L2.log { Timber.i(t, message) } + + @JvmStatic + fun i(message: String, vararg args: Any) = L2.log { Timber.i(message, *args) } + + @JvmStatic + fun i(message: String) = L2.log { Timber.i(message) } + + @JvmStatic + fun w(t: Throwable?) = L2.log { Timber.w(t) } + + @JvmStatic + fun w(t: Throwable? = null, message: String, vararg args: Any) = L2.log { Timber.w(t, message, *args) } + + @JvmStatic + fun w(t: Throwable? = null, message: String) = L2.log { Timber.w(t, message) } + + @JvmStatic + fun w(message: String, vararg args: Any) = L2.log { Timber.w(message, *args) } + + @JvmStatic + fun w(message: String) = L2.log { Timber.w(message) } + + @JvmStatic + fun e(t: Throwable?) = L2.log { Timber.e(t) } + + @JvmStatic + fun e(t: Throwable? = null, message: String, vararg args: Any) = L2.log { Timber.e(t, message, *args) } + + @JvmStatic + fun e(t: Throwable? = null, message: String) = L2.log { Timber.e(t, message) } + + @JvmStatic + fun e(message: String, vararg args: Any) = L2.log { Timber.e(message, *args) } + + @JvmStatic + fun e(message: String) = L2.log { Timber.e(message) } + + @JvmStatic + fun wtf(t: Throwable?) = L2.log { Timber.wtf(t) } + + @JvmStatic + fun wtf(t: Throwable? = null, message: String, vararg args: Any) = L2.log { Timber.wtf(t, message, *args) } + + @JvmStatic + fun wtf(t: Throwable? = null, message: String) = L2.log { Timber.wtf(t, message) } + + @JvmStatic + fun wtf(message: String, vararg args: Any) = L2.log { Timber.wtf(message, *args) } + + @JvmStatic + fun wtf(message: String) = L2.log { Timber.wtf(message) } + + // -------------- + // helper function + // -------------- + + fun log(logBlock: () -> Unit) { + if (L.enabled && Timber.treeCount() > 0) { + setCallStackCorrection(4) + logBlock() + } + } + + private fun setCallStackCorrection(correction: Int) { + val forest = Timber.forest() + var i = 0 + for (tree in forest) { + if (tree is BaseTree) { + tree.setCallStackCorrection(correction) + } + } + } +} 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 2890f43..0552513 100644 --- a/library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt +++ b/library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt @@ -33,17 +33,4 @@ class StackData(private val className: String, private val simpleFileName: Strin fun getStackTag() = "$simpleClassName:$line $methodName" fun getLink() = "$simpleFileName:$line" - - fun appendLink(source: String): String { - val lines = source.split("\r\n|\r|\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (lines.size <= 1) - return "$source (${getLink()})" - else { - lines[0] = lines[0] + " (" + getLink() + ")" - val builder = StringBuilder() - for (s in lines) - builder.append(s).append("\n") - return builder.toString() - }// this makes sure that links always works, like for example if pretty print for collections is enabled - } } \ 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 a699702..2142e7e 100644 --- a/library/src/main/java/timber/log/BaseTree.kt +++ b/library/src/main/java/timber/log/BaseTree.kt @@ -13,16 +13,36 @@ abstract class BaseTree : Timber.Tree() { internal val CALL_STACK_INDEX = 6 } + private val callStackCorrection = ThreadLocal() + + protected lateinit var lastStackData: StackData + + fun getCallStackCorrection(): Int? { + val correction = callStackCorrection.get() + if (correction != null) { + callStackCorrection.remove() + } + return correction + } + + fun setCallStackCorrection(value: Int) { + callStackCorrection.set(value) + } + internal override fun getTag(): String? { - // 1) return default tag if one exists + + // 1) get stack data + var callStackCorrection = getCallStackCorrection() ?: 0 + lastStackData = StackData.create(CALL_STACK_INDEX + callStackCorrection) + + // 2) return default tag if one exists val tag = super.getTag() if (tag != null) { return tag } - // 2) create a custom tag for the logs => we use the - val stackData = StackData.create(CALL_STACK_INDEX) - return "[${stackData.getStackTag()}]" + // 3) create a custom tag for the logs => we use the + return "[${lastStackData.getStackTag()}]" } protected fun formatLine(tag: String?, message: String) = "[$tag]: $message" diff --git a/library/src/main/java/timber/log/ConsoleTree.kt b/library/src/main/java/timber/log/ConsoleTree.kt index 6f3d7a5..7a9be16 100644 --- a/library/src/main/java/timber/log/ConsoleTree.kt +++ b/library/src/main/java/timber/log/ConsoleTree.kt @@ -50,8 +50,7 @@ class ConsoleTree(val appendClickableLink: Boolean = true) : BaseTree() { } private fun appendLink(message: String): String { - val stackData = StackData.create(CALL_STACK_INDEX) - val link = stackData.getLink() + val link = lastStackData.getLink() val lines = message.split("\r\n|\r|\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() if (lines.size <= 1) { return message + " (" + link + ")"