Introduce Throwable.stackTraceToString

#KT-37603

(cherry picked from commit 1cc88979314ae8bb48ad77625fdd5bce91dd74a8)
This commit is contained in:
Ilya Gorbunov
2020-03-17 07:25:35 +03:00
committed by Vasily Levchenko
parent 96c73b2869
commit f0224c6c07
+37 -15
View File
@@ -43,34 +43,45 @@ public open class Throwable(open val message: String?, open val cause: Throwable
(0 until stackTrace.size).map { index -> stackTrace[index].toLong() }
/**
* Prints the stack trace of this throwable to the standard output.
* Prints the [detailed description][Throwable.stackTraceToString] of this throwable to the standard output.
*/
public fun printStackTrace(): Unit = dumpStackTrace { println(it) }
public fun printStackTrace(): Unit = dumpStackTrace("", "") { println(it) }
internal fun dumpStackTrace(): String = buildString {
dumpStackTrace { appendln(it) }
dumpStackTrace("", "") { appendln(it) }
}
private inline fun writeStackTraceElements(throwable: Throwable, writeln: (String) -> Unit) {
for (element in throwable.stackTraceStrings) {
writeln(" at $element")
}
}
private inline fun dumpStackTrace(crossinline writeln: (String) -> Unit) {
writeln(this@Throwable.toString())
writeStackTraceElements(this, writeln)
private fun Throwable.dumpStackTrace(indent: String, qualifier: String, writeln: (String) -> Unit) {
this.dumpSelfTrace(indent, qualifier, writeln)
var cause = this.cause
while (cause != null) {
// TODO: should skip common stack frames
writeln("Caused by: $cause")
writeStackTraceElements(cause, writeln)
cause.dumpSelfTrace(indent, "Caused by: ", writeln)
cause = cause.cause
}
}
private fun Throwable.dumpSelfTrace(indent: String, qualifier: String, writeln: (String) -> Unit) {
writeln(indent + qualifier + this.toString())
for (element in stackTraceStrings) {
writeln("$indent\tat $element")
}
val suppressed = suppressedExceptionsList
if (!suppressed.isNullOrEmpty()) {
val suppressedIndent = indent + '\t'
for (s in suppressed) {
s.dumpStackTrace(suppressedIndent, "Suppressed: ", writeln)
}
}
}
/**
* Returns the short description of this throwable consisting of
* the exception class name (fully qualified if possible)
* followed by the exception message if it is not null.
*/
public override fun toString(): String {
val kClass = this::class
val s = kClass.qualifiedName ?: kClass.simpleName ?: "Throwable"
@@ -86,6 +97,17 @@ private external fun getCurrentStackTrace(): NativePtrArray
@SymbolName("Kotlin_getStackTraceStrings")
private external fun getStackTraceStrings(stackTrace: NativePtrArray): Array<String>
/**
* 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 = dumpStackTrace()
/**
* Adds the specified exception to the list of exceptions that were