diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageLogCollector.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageLogCollector.kt index 4308388a..2ad00c30 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageLogCollector.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageLogCollector.kt @@ -5,8 +5,8 @@ import net.dankito.banking.fints.model.MessageLogEntry import net.dankito.banking.fints.model.MessageLogEntryType import net.dankito.utils.multiplatform.log.Logger import net.dankito.utils.multiplatform.log.LoggerFactory -import net.dankito.utils.multiplatform.StackTraceHelper import net.dankito.utils.multiplatform.extensions.getInnerException +import net.dankito.utils.multiplatform.extensions.nthIndexOf import net.dankito.utils.multiplatform.extensions.toStringWithTwoDigits import kotlin.reflect.KClass @@ -32,9 +32,6 @@ open class MessageLogCollector { get() = ArrayList(messageLog) - protected open val stackTraceHelper = StackTraceHelper() - - open fun addMessageLog(type: MessageLogEntryType, message: String, context: MessageContext) { val messageToLog = createMessage(type, prettyPrintHbciMessage(message), context, true) @@ -50,7 +47,7 @@ open class MessageLogCollector { if (e != null) { getLogger(loggingClass).error(e) { messageToLog } } else { - getLogger(loggingClass).error(messageToLog) + getLogger(loggingClass).error { messageToLog } } val errorStackTrace = if (e != null) NewLine + getStackTrace(e) else "" @@ -145,7 +142,10 @@ open class MessageLogCollector { protected open fun getStackTrace(e: Exception): String { val innerException = e.getInnerException() - return stackTraceHelper.getStackTrace(innerException, MaxCountStackTraceElements) + val stackTraceString = innerException.stackTraceToString() + val indexOf16thLine = stackTraceString.nthIndexOf("\n", MaxCountStackTraceElements) + + return if (indexOf16thLine < 0) stackTraceString else stackTraceString.substring(0, indexOf16thLine) } protected open fun getLogger(loggingClass: KClass<*>): Logger { diff --git a/multiplatform-utils/src/commonMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt b/multiplatform-utils/src/commonMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt deleted file mode 100644 index 50a508a6..00000000 --- a/multiplatform-utils/src/commonMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.dankito.utils.multiplatform - - -expect class StackTraceHelper actual constructor() { - - fun getStackTrace(e: Throwable, maxCountStackTraceElements: Int? = null): String - -} \ No newline at end of file diff --git a/multiplatform-utils/src/commonMain/kotlin/net/dankito/utils/multiplatform/extensions/StringExtensions.kt b/multiplatform-utils/src/commonMain/kotlin/net/dankito/utils/multiplatform/extensions/StringExtensions.kt new file mode 100644 index 00000000..fa71efef --- /dev/null +++ b/multiplatform-utils/src/commonMain/kotlin/net/dankito/utils/multiplatform/extensions/StringExtensions.kt @@ -0,0 +1,53 @@ +package net.dankito.utils.multiplatform.extensions + + +/** + * Returns the n-th occurrence of [string] or -1 if [string] isn't contained n-times. + */ +fun String.nthIndexOf(string: String, nthOccurrence: Int, startIndex: Int = 0, ignoreCase: Boolean = false): Int { + var currentIndex = startIndex + var countOccurrence = 0 + + while (countOccurrence < nthOccurrence) { + val index = this.indexOf(string, currentIndex, ignoreCase) + + if (index < 0) { + return -1 // not found + } + + if (++countOccurrence == nthOccurrence) { + return index + } + + currentIndex = index + 1 + } + + return -1 +} + +/** + * Finds all occurrences of [string] in String and returns their indices. + */ +fun String.indicesOf(string: String, startIndex: Int = 0, ignoreCase: Boolean = false): List { + val indices = mutableListOf() + var currentIndex = startIndex + + while (currentIndex >= 0) { + currentIndex = this.indexOf(string, currentIndex, ignoreCase) + + if (currentIndex < 0) { + break + } else { + indices.add(currentIndex++) + } + } + + return indices +} + +/** + * Finds all occurrences of [string] in String. + */ +fun String.countOccurrences(string: String, startIndex: Int = 0, ignoreCase: Boolean = false): Int { + return this.indicesOf(string, startIndex, ignoreCase).size +} \ No newline at end of file diff --git a/multiplatform-utils/src/commonTest/kotlin/net.dankito.utils.multiplatform.extensions/StringExtensionsTest.kt b/multiplatform-utils/src/commonTest/kotlin/net.dankito.utils.multiplatform.extensions/StringExtensionsTest.kt new file mode 100644 index 00000000..375b2b46 --- /dev/null +++ b/multiplatform-utils/src/commonTest/kotlin/net.dankito.utils.multiplatform.extensions/StringExtensionsTest.kt @@ -0,0 +1,42 @@ +package net.dankito.utils.multiplatform.extensions + +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class StringExtensionsTest { + + @Test + fun nthIndexOf() { + val input = "java.lang.Exception: A severe error occurred" + IntRange(1, 30).map { "\r\n\tStack trace element $it" } + + val result = input.nthIndexOf("\n", 15) + + assertEquals(415, result) + } + + @Test + fun countOccurrences() { + val expectedOccurrences = 30 + val input = "java.lang.Exception: A severe error occurred" + IntRange(1, expectedOccurrences).map { "\r\n\tStack trace element $it" } + + val result = input.countOccurrences("\n") + + assertEquals(expectedOccurrences, result) + } + + @Test + fun indicesOf() { + val expectedOccurrences = 30 + val stringToFind = "\r\n" + val input = "java.lang.Exception: A severe error occurred" + IntRange(1, expectedOccurrences).map { "$stringToFind\tStack trace element $it" } + + val result = input.indicesOf(stringToFind) + + assertEquals(expectedOccurrences, result.size) + + result.forEach { index -> + assertEquals(input.substring(index, index + stringToFind.length), stringToFind) + } + } + +} \ No newline at end of file diff --git a/multiplatform-utils/src/iosMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt b/multiplatform-utils/src/iosMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt deleted file mode 100644 index 45db401b..00000000 --- a/multiplatform-utils/src/iosMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt +++ /dev/null @@ -1,16 +0,0 @@ -package net.dankito.utils.multiplatform - - -actual class StackTraceHelper() { - - actual fun getStackTrace(e: Throwable, maxCountStackTraceElements: Int?): String { - var stackTrace = e.getStackTrace() - - maxCountStackTraceElements?.let { - stackTrace = stackTrace.take(maxCountStackTraceElements) - } - - return stackTrace.joinToString("\r\n") - } - -} \ No newline at end of file diff --git a/multiplatform-utils/src/jvmMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt b/multiplatform-utils/src/jvmMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt deleted file mode 100644 index 33aae61d..00000000 --- a/multiplatform-utils/src/jvmMain/kotlin/net/dankito/utils/multiplatform/StackTraceHelper.kt +++ /dev/null @@ -1,24 +0,0 @@ -package net.dankito.utils.multiplatform - -import java.io.PrintWriter -import java.io.StringWriter - - -actual class StackTraceHelper { - - actual fun getStackTrace(e: Throwable, maxCountStackTraceElements: Int?): String { - val stringWriter = StringWriter() - e.printStackTrace(PrintWriter(stringWriter)) - - val stackTrace = stringWriter.toString() - - maxCountStackTraceElements?.let { - val elements = stackTrace.split(System.lineSeparator()).take(maxCountStackTraceElements) - - return elements.joinToString(System.lineSeparator()) - } - - return stackTrace - } - -} \ No newline at end of file diff --git a/multiplatform-utils/src/nativeMain/kotlin/net.dankito.utils.multiplatform/StackTraceHelper.kt b/multiplatform-utils/src/nativeMain/kotlin/net.dankito.utils.multiplatform/StackTraceHelper.kt deleted file mode 100644 index a2d8fe3e..00000000 --- a/multiplatform-utils/src/nativeMain/kotlin/net.dankito.utils.multiplatform/StackTraceHelper.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.dankito.utils.multiplatform - -actual class StackTraceHelper { - - actual fun getStackTrace(e: Throwable, maxCountStackTraceElements: Int?): String { - // TODO: is this a nice string? - return e.getStackTrace().take(maxCountStackTraceElements ?: Int.MAX_VALUE).joinToString("\n") - } - -} \ No newline at end of file