i am experimenting with KLogging a bit is there an...
# kotlin-logging
n
i am experimenting with KLogging a bit is there any way to get filename + linenumber in the console/stdout output ? i want to make use of the fact that idea converts
.(Main.kt:23)
into a clickable link i eneded up making a custom renderer and
${level}F
overloads that throws and catches to get the stacktrace.. its not clean.. but timing measurements show it only costs 100us on average.. good enough for me
m
Hey @Nikky thanks for trying Klogging! I have not implemented filename + line number but will look at it if there is demand. Do you have some code you can share? —Michael (creator of Klogging)
n
i use this function to grab the info fro mthe stacktrace:
Copy code
fun getLocation(): String? {
    if (!scanStacktrace) return null
    return try {
        throw Exception()
    } catch (e: Exception) {
        val firstElement = e.stackTrace.first()
        e.stackTrace.firstOrNull { element ->
            element.fileName != firstElement.fileName
                    && element.lineNumber > 0
                    && element.className.startsWith("moe.nikky.")
        }?.let { element ->
            "${element.fileName}:${element.lineNumber}"
        }.also {
            if (it == null) e.printStackTrace()
        }
    }
}
would probably be better to just add a
callsite: StackTraceElement?
to
LogEvent
and a flag in the log configuration whether to grab the stacktraces or not.. creating sand catching stacktraces is (relatively) expensive currently i store in in the log context and remove it before printing the items, not so clean.. but i did not want to fork Klogging (yet)
Copy code
val CUSTOM_RENDERER: RenderString = { e: LogEvent ->
    val loggerOrFile = e.items["file"]?.let { ".($it)" } ?: e.logger
    val time = e.timestamp.localString.padEnd(29, '0')
    val message = "$time ${e.level} $loggerOrFile : ${e.evalTemplate()}"
    val cleanedItems = e.items - "file"
    val maybeItems = if (cleanedItems.isNotEmpty()) " : $cleanedItems" else ""
    val maybeStackTrace = if (e.stackTrace != null) "\n${e.stackTrace}" else ""
    message + maybeItems + maybeStackTrace
}
c
Something slightly less expensive and a bit more intention-revealing than throwing an exception to get the stack trace would be using Thread.getStackTrace() (this will only work on the JVM though)
o
log4j and logback both use the stack trace of a newly created
Throwable()
in combination with the fully qualified caller class name for location information: • log4j sourcelogback source As logback is supposedly better at figuring out line numbers, it might be worth a look. Browsers offer a similar capability via the
Error()
object: https://stackoverflow.com/a/2343382/2529022. However, as such stack traces normally refer to minified code they will require further decoding via source maps.
For performant logging with line numbers, a compiler plugin would be ideal, which would also probably be the only option available for native platforms.
n
i think i'd rather wait for those to be documented, although i guess it might help with a lot of other things that are limiting on native and js
also.. thanks for the hint about
thread.getStrackTrace()
Copy code
fun getLocation(): String? {
    if (!scanStacktrace) return null
    val stackTrace = Thread.currentThread().stackTrace.drop(1)
    val firstElement = stackTrace.first()
    return stackTrace.firstOrNull { element ->
        element.fileName != firstElement.fileName
                && element.lineNumber > 0
                && element.className.startsWith("moe.nikky.")
    }?.let { element ->
        "${element.fileName}:${element.lineNumber}"
    }.also {
        if (it == null) System.err.println(stackTrace.joinToString("\n  at "))
    }
}
this code seems to be more performant
o
I'd also be hesitant with plugin development, though I feel it's good to know that the option is on the table. 🙂