From 4edb5069e82e967e754f802fcc11227176c2b707 Mon Sep 17 00:00:00 2001 From: Ruslan Burdeniuk Date: Tue, 17 Feb 2026 10:44:39 +0200 Subject: [PATCH 1/3] DRMCDU-1534: remove exception stacktrace from failure details --- library/failure/api/failure-library.api | 2 - .../uframework/failure/Failure.kt | 6 +-- .../uframework/failure/TypeFailure.kt | 1 - .../failure/AllDetailsFailureTest.kt | 54 ++++++------------- 4 files changed, 16 insertions(+), 47 deletions(-) diff --git a/library/failure/api/failure-library.api b/library/failure/api/failure-library.api index 782b651f..dc8d7597 100644 --- a/library/failure/api/failure-library.api +++ b/library/failure/api/failure-library.api @@ -119,14 +119,12 @@ public final class io/github/ustudiocompany/uframework/failure/FailureKt { public abstract interface class io/github/ustudiocompany/uframework/failure/TypeFailure : io/github/ustudiocompany/uframework/failure/Failure { public static final field ACTUAL_VALUE_DETAIL_KEY Ljava/lang/String; public static final field Companion Lio/github/ustudiocompany/uframework/failure/TypeFailure$Companion; - public static final field EXCEPTION_STACKTRACE Ljava/lang/String; public static final field PATTERN_DETAIL_KEY Ljava/lang/String; public abstract fun getType-uX7CcE4 ()Ljava/lang/Class; } public final class io/github/ustudiocompany/uframework/failure/TypeFailure$Companion { public static final field ACTUAL_VALUE_DETAIL_KEY Ljava/lang/String; - public static final field EXCEPTION_STACKTRACE Ljava/lang/String; public static final field PATTERN_DETAIL_KEY Ljava/lang/String; } diff --git a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt index 9c1580d2..44747939 100644 --- a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt +++ b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/Failure.kt @@ -2,7 +2,6 @@ package io.github.ustudiocompany.uframework.failure import io.github.ustudiocompany.uframework.failure.Failure.Cause import io.github.ustudiocompany.uframework.failure.Failure.Details -import io.github.ustudiocompany.uframework.failure.TypeFailure.Companion.EXCEPTION_STACKTRACE public interface Failure { /** @@ -123,16 +122,13 @@ public fun Failure.fullCode(delimiter: String = "."): String = }.toString() /** - * Returns all details of the failure, its causes, and root exception details if it exists. + * Returns all details of the failure and its causes. * @return the all details. */ public fun Failure.allDetails(): Details { val allDetails = fold(initial = { mutableListOf().apply { addAll(it.details) } }) { acc, failure -> acc.apply { addAll(failure.details) } } - val exception = root().exceptionOrNull() - if (exception != null) - allDetails.add(Details.Item(key = EXCEPTION_STACKTRACE, value = exception.stackTraceToString())) return if (allDetails.isEmpty()) Details.NONE else diff --git a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt index ab1d9daf..c7bf258f 100644 --- a/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt +++ b/library/failure/src/main/kotlin/io/github/ustudiocompany/uframework/failure/TypeFailure.kt @@ -6,6 +6,5 @@ public interface TypeFailure : Failure { public companion object { public const val ACTUAL_VALUE_DETAIL_KEY: String = "actual-value" public const val PATTERN_DETAIL_KEY: String = "pattern" - public const val EXCEPTION_STACKTRACE: String = "exception-stackTrace" } } diff --git a/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt b/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt index f12c72dd..5ab74a51 100644 --- a/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt +++ b/library/failure/src/test/kotlin/io/github/ustudiocompany/uframework/failure/AllDetailsFailureTest.kt @@ -2,7 +2,6 @@ package io.github.ustudiocompany.uframework.failure import io.github.ustudiocompany.uframework.failure.Failure.Cause import io.github.ustudiocompany.uframework.failure.Failure.Details -import io.github.ustudiocompany.uframework.failure.TypeFailure.Companion.EXCEPTION_STACKTRACE import io.github.ustudiocompany.uframework.test.kotest.UnitTest import io.kotest.datatest.withData import io.kotest.matchers.collections.shouldContainOnly @@ -15,38 +14,29 @@ internal class AllDetailsFailureTest : UnitTest() { withData( nameFn = { (failure, _) -> failure.toString() }, listOf( - failureRoot(code = CODE_1) to - Details.NONE, - failureRootException(details = Details.of(KEY_1 to VALUE_1)) to - Details.of( - KEY_1 to VALUE_1, - EXCEPTION_STACKTRACE to VALUE_4 - ), - failureChild(code = CODE_2, cause = failureRoot(code = CODE_1)) to - Details.NONE, - failureChild( + failure(code = CODE_1) to Details.NONE, + failure(code = CODE_1, details = Details.of(KEY_1 to VALUE_1)) to Details.of(KEY_1 to VALUE_1), + failure(code = CODE_2, cause = failure(code = CODE_1)) to Details.NONE, + failure( code = CODE_2, - cause = failureRoot(CODE_1), + cause = failure(CODE_1), details = Details.of(KEY_1 to VALUE_1) - ) to - Details.of(KEY_1 to VALUE_1), - failureChild( + ) to Details.of(KEY_1 to VALUE_1), + failure( code = CODE_2, - cause = failureRoot( + cause = failure( code = CODE_1, details = Details.of(KEY_1 to VALUE_1) ) - ) to - Details.of(KEY_1 to VALUE_1), - failureChild( + ) to Details.of(KEY_1 to VALUE_1), + failure( code = CODE_2, - cause = failureRoot( + cause = failure( code = CODE_1, details = Details.of(KEY_1 to VALUE_1) ), details = Details.of(KEY_2 to VALUE_2) - ) to - Details.of(KEY_1 to VALUE_1, KEY_2 to VALUE_2) + ) to Details.of(KEY_1 to VALUE_1, KEY_2 to VALUE_2) ) ) { (failure, expected) -> failure.allDetails() shouldContainOnly expected @@ -54,13 +44,8 @@ internal class AllDetailsFailureTest : UnitTest() { } } - private fun failureRoot(code: String, details: Details = Details.NONE): Failure = - Root(code = code, details = details) - - private fun failureRootException(code: String = CODE_1, details: Details = Details.NONE): Failure = - RootException(code = code, details = details) - - private fun failureChild(code: String, cause: Failure, details: Details = Details.NONE): Failure = + private fun failure(code: String, details: Details = Details.NONE): Failure = Root(code = code, details = details) + private fun failure(code: String, cause: Failure, details: Details = Details.NONE): Failure = Child(code = code, cause = Cause.Failure(cause), details = details) private companion object { @@ -71,20 +56,11 @@ internal class AllDetailsFailureTest : UnitTest() { private const val KEY_2 = "key-2" private const val VALUE_1 = "value-1" private const val VALUE_2 = "value-2" - private const val VALUE_3 = "value-3" - private val testException = Exception(VALUE_3) - private val VALUE_4 = testException.stackTraceToString() } private data class Root( override val code: String, - override val details: Details = Details.NONE, - ) : Failure - - private data class RootException( - override val code: String, - override val details: Details = Details.NONE, - override val cause: Cause = Cause.Exception(testException) + override val details: Details = Details.NONE ) : Failure private data class Child( From 939e4c67a0a651f503eb3b8cbf91f03ef20c873f Mon Sep 17 00:00:00 2001 From: Ruslan Burdeniuk Date: Tue, 17 Feb 2026 11:49:04 +0200 Subject: [PATCH 2/3] DRMCDU-1534: refactor transaction logic --- library/jdbc/core/api/jdbc-core-library.api | 1 + .../jdbc/transaction/TransactionInstance.kt | 46 ++++++++++--------- .../jdbc/transaction/TransactionManager.kt | 13 ++++-- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/library/jdbc/core/api/jdbc-core-library.api b/library/jdbc/core/api/jdbc-core-library.api index db6ac97f..24915297 100644 --- a/library/jdbc/core/api/jdbc-core-library.api +++ b/library/jdbc/core/api/jdbc-core-library.api @@ -240,6 +240,7 @@ public final class io/github/ustudiocompany/uframework/jdbc/transaction/Transact } public final class io/github/ustudiocompany/uframework/jdbc/transaction/TransactionManagerKt { + public static final fun getLogger ()Lorg/slf4j/Logger; public static final fun useTransaction (Lio/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager;Lio/github/ustudiocompany/uframework/jdbc/transaction/TransactionIsolation;Lkotlin/jvm/functions/Function1;)Lio/github/airflux/commons/types/resultk/ResultK; public static final fun useTransaction (Lio/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager;Lio/github/ustudiocompany/uframework/jdbc/transaction/TransactionIsolation;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lio/github/airflux/commons/types/resultk/ResultK; public static synthetic fun useTransaction$default (Lio/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager;Lio/github/ustudiocompany/uframework/jdbc/transaction/TransactionIsolation;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/airflux/commons/types/resultk/ResultK; diff --git a/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt b/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt index a65fdd33..b87c5eaf 100644 --- a/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt +++ b/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt @@ -3,6 +3,7 @@ package io.github.ustudiocompany.uframework.jdbc.transaction import io.github.airflux.commons.types.maybe.Maybe +import io.github.airflux.commons.types.maybe.onNone import io.github.airflux.commons.types.resultk.ResultK import io.github.airflux.commons.types.resultk.map import io.github.ustudiocompany.uframework.jdbc.JDBCResult @@ -16,9 +17,9 @@ import io.github.ustudiocompany.uframework.jdbc.statement.JDBCPreparedStatementI import io.github.ustudiocompany.uframework.jdbc.statement.JDBCStatement import io.github.ustudiocompany.uframework.telemetry.logging.logger.slf4jextension.debug import io.github.ustudiocompany.uframework.telemetry.logging.logger.slf4jextension.error -import io.github.ustudiocompany.uframework.telemetry.logging.logger.slf4jextension.warn import java.sql.Connection import java.sql.PreparedStatement +import java.sql.SQLException import org.slf4j.LoggerFactory internal class TransactionInstance( @@ -30,34 +31,35 @@ internal class TransactionInstance( override val connection: JDBCConnection get() = this - override fun commit(): Maybe = Maybe.catch( - catch = { exception -> - val errorDescription = "Error while committing transaction." - logger.error { errorDescription } - JDBCError(description = errorDescription, exception = exception) - }, - block = { unwrappedConnection.commit() } - ) + override fun commit(): Maybe { + logger.debug("Commit transaction started.") + return Maybe.catch( + block = { unwrappedConnection.commit() }, + catch = { exception -> + JDBCError(description = "Error while committing transaction.", exception = exception) + } + ).onNone { logger.debug("Commit transaction finished.") } + } - override fun rollback(): Maybe = Maybe.catch( - catch = { exception -> - val errorDescription = "Error while rolling back transaction." - logger.error { errorDescription } - JDBCError(description = errorDescription, exception = exception) - }, - block = { - logger.warn { "Transaction would be rolled back." } - unwrappedConnection.rollback() - } - ) + override fun rollback(): Maybe { + logger.debug("Rollback transaction started.") + return Maybe.catch( + block = { unwrappedConnection.rollback() }, + catch = { exception -> + JDBCError(description = "Error while rolling back transaction.", exception = exception) + } + ).onNone { logger.debug("Rollback transaction finished.") } + } override fun close() { + logger.debug("Closing transaction connection.") try { if (!unwrappedConnection.isClosed) unwrappedConnection.close() - } catch (_: Exception) { - // ignore + } catch (e: SQLException) { + logger.error(e) { "Error occurred while closing connection." } } + logger.debug("Transaction connection closed.") } override fun preparedStatement( diff --git a/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager.kt b/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager.kt index 577f53bd..17372abc 100644 --- a/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager.kt +++ b/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionManager.kt @@ -10,6 +10,9 @@ import io.github.ustudiocompany.uframework.jdbc.JDBCResult import io.github.ustudiocompany.uframework.jdbc.connection.JDBCConnection import io.github.ustudiocompany.uframework.jdbc.error.JDBCError import io.github.ustudiocompany.uframework.jdbc.use +import io.github.ustudiocompany.uframework.telemetry.logging.logger.slf4jextension.debug +import org.slf4j.Logger +import org.slf4j.LoggerFactory /** * A transaction manager that provides a way to start a transaction. @@ -100,6 +103,8 @@ public interface TransactionManager { ): JDBCResult } +public val logger: Logger = LoggerFactory.getLogger(TransactionManager::class.java) + public inline fun TransactionManager.useTransaction( isolation: TransactionIsolation = TransactionIsolation.READ_COMMITTED, block: (JDBCConnection) -> TransactionResult @@ -114,6 +119,7 @@ public inline fun TransactionManager.us startTransaction(isolation) .mapFailure { fail -> exceptionBuilder(fail) } .use { tx -> + logger.debug { "Transaction started." } val result = try { block(tx.connection) } catch (expected: Exception) { @@ -127,8 +133,9 @@ public inline fun TransactionManager.us onNone = { result }, onSome = { error -> exceptionBuilder(error).asException().asFailure() } ) - else { + else tx.rollback() - result - } + + logger.debug { "Transaction ended." } + result } From ba33187187cc9b25af17b83c2c053e7905f5189c Mon Sep 17 00:00:00 2001 From: Ruslan Burdeniuk Date: Tue, 17 Feb 2026 14:31:38 +0200 Subject: [PATCH 3/3] DRMCDU-1534: change Exception --- .../uframework/jdbc/transaction/TransactionInstance.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt b/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt index b87c5eaf..04d059ff 100644 --- a/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt +++ b/library/jdbc/core/src/main/kotlin/io/github/ustudiocompany/uframework/jdbc/transaction/TransactionInstance.kt @@ -19,7 +19,6 @@ import io.github.ustudiocompany.uframework.telemetry.logging.logger.slf4jextensi import io.github.ustudiocompany.uframework.telemetry.logging.logger.slf4jextension.error import java.sql.Connection import java.sql.PreparedStatement -import java.sql.SQLException import org.slf4j.LoggerFactory internal class TransactionInstance( @@ -56,8 +55,8 @@ internal class TransactionInstance( try { if (!unwrappedConnection.isClosed) unwrappedConnection.close() - } catch (e: SQLException) { - logger.error(e) { "Error occurred while closing connection." } + } catch (expected: Exception) { + logger.error(expected) { "Error occurred while closing connection." } } logger.debug("Transaction connection closed.") }