The well known and loved stack trace was just a spoil of the JVM, it does not exist on JS (idk about native), so it makes sense that it’s missing in common code.
Indeed when trying to println(e) an error in multiplatform it just prints out the message and not where it happened! Also printStackTrace() is JVM only.
I was wondering if there was a clever and concise way to create an error stack.
My first thought went to a hierarchical re-throw of errors where upper Throwable has the inner as cause and make their toString() pretty:
data class MyCoolError(override val cause: Throwable) : Throwable()
// somewhere in my sh***y code
try {
possiblyErroringLine()
} catch (e: Throwable) {
throw MyCoolError(e)
}
But this approach throws (pun intended) you into the try-catch hell once again since you need to wrap every possible line that may errors.
Now if you test your K/MPP library in JVM and let it crash you do get the stack trace printed. But what if you want to catch and log the errors in common code? There is no stack trace there!
I use this log function to see expanded errors on the console. Also, I use a general wrapper for event handlers / async functions to call this in case of error:
fun log(ex: Throwable?): String {
if (ex == null) return ""
val stack = ex.asDynamic().stack
return if (stack is String) {
val error = js("Error()")
error.name = ex.toString().substringBefore(':')
error.message = ex.message?.substringAfter(':')
error.stack = stack
@Suppress("UnsafeCastFromDynamic") // magic, this whole function is pure magic
console.error(error)
error.toString()
} else {
console.log(ex)
ex.toString()
}
}