11

I am using kotlin.logging as my logging framework for an application.

I would like to be able to log the stack trace in a much more readable way (maybe JSON format):

I am doing the following, but it results in a very verbose/unreadable format:

logger.error("Exception caught in handleIllegalArgumentsException: $e", e.printStackTrace())

when logging the Throwable exception only (see below), it does not show the stack trace:

logger.error("Exception caught in handleIllegalArgumentsException: $e") 
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
D.B
  • 4,009
  • 14
  • 46
  • 83
  • What is kotlin.logging? Do you have a link to it its website or repo? I am aware of [kotlin-logging](https://github.com/oshai/kotlin-logging), spelt with a hyphen, and perhaps that's what you mean, but I can't find any hint that it also goes by the name "kotlin.logging" (with a dot) nor can I find another library with that name. – Mark Amery Mar 16 '23 at 13:30

4 Answers4

13

You should be able to get stack trace using the following way.

logger.error(e) { 
    "Exception caught in handleIllegalArgumentsException" 
}
mmmmmm
  • 32,227
  • 27
  • 88
  • 117
chom
  • 651
  • 3
  • 9
  • 23
9

For the people getting here through a google search:

Since Kotlin 1.4 Throwable has an extension method that allows you to get the Stack Trace as a String, which basically does what is suggested by other answers.


/**
 * Returns the detailed description of this throwable with its stack trace.
 *
 * The detailed description includes:
 * - the short description (see [Throwable.toString]) of this throwable;
 * - the complete stack trace;
 * - detailed descriptions of the exceptions that were [suppressed][suppressedExceptions] in order to deliver this exception;
 * - the detailed description of each throwable in the [Throwable.cause] chain.
 */
@SinceKotlin("1.4")
public actual fun Throwable.stackTraceToString(): String {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    printStackTrace(pw)
    pw.flush()
    return sw.toString()
}

This means the original e.printStackTrace() just needs to be changed into e.stackTraceToString()

Like so:

logger.error("Exception caught in handleIllegalArgumentsException: ${e.stackTraceToString()}") 
Antero Duarte
  • 293
  • 1
  • 4
  • 20
2

If you want the logger to print the exception stacktrace:

try {
    ...
} catch (e: Exception) {
    logger.error("Exception caught:", e)
}

If you want the string itself (for further manipulation), you can use what @Михаил Нафталь suggested:

try {
    ...
} catch (e: Exception) {
    val stacktrace = StringWriter().also { e.printStackTrace(PrintWriter(it)) }.toString().trim()
    logger.error("Exception caught: $stacktrace")
}

Both these methods will print the whole stacktrace in the logs, for example:

16:41:50.528 [main] ERROR org.myorg.MyClass - Exception caught:
java.lang.IllegalArgumentException: Argument X was not allowed.
    at org.myorg.MyClass.func (MyClass.kt:124)
    at java.base/java.lang.Thread.run(Thread.java:834)
    etc...

I know it's not answering to what is asked in the question text, but it's answering to the question title. As this post was the first suggestion I got when googling how to log stacktraces with Kotlin, I thought this might help others.

jinnlao
  • 1,341
  • 1
  • 9
  • 6
0

Stacktrace is always a multiline, while conventional logging message should be one-lined. So you need to first save it to a String variable, and then somehow replace line-breaking symbols (with | symbol for instance):

logger.error {
    val stacktrace = StringWriter().also { e.printStackTrace(PrintWriter(it)) }.toString().trim()
    val singleLineStackTrace = stacktrace.lines().map { it.trim() }.joinToString(separator = "|")
    "Exception caught in handleIllegalArgumentsException: $singleLineStackTrace"
}

Then log will look like this:

[main] ERROR Logging - Exception caught in handleIllegalArgumentsException: java.lang.IllegalArgumentException: !!!!|at LoggingKt.main(logging.kt:12)|at LoggingKt.main(logging.kt)