Skip to content

Commit

Permalink
code clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
MFlisar committed Oct 22, 2020
1 parent 3e02d11 commit 292bece
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand All @@ -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()}" }
}
}

Expand Down
8 changes: 7 additions & 1 deletion library/src/main/java/com/michaelflisar/lumberjack/L.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
// --------------
Expand Down Expand Up @@ -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()
}
}
Expand Down
110 changes: 86 additions & 24 deletions library/src/main/java/com/michaelflisar/lumberjack/data/StackData.kt
Original file line number Diff line number Diff line change
@@ -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<StackTraceElement>, 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)
}
}
6 changes: 3 additions & 3 deletions library/src/main/java/timber/log/BaseTree.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()}]"
}
}

Expand Down
4 changes: 2 additions & 2 deletions library/src/main/java/timber/log/ConsoleTree.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}

0 comments on commit 292bece

Please sign in to comment.