diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageContext.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageContext.kt new file mode 100644 index 00000000..3c4a59cb --- /dev/null +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/log/MessageContext.kt @@ -0,0 +1,12 @@ +package net.dankito.banking.fints.log + +import net.dankito.banking.fints.model.AccountData +import net.dankito.banking.fints.model.BankData + + +class MessageContext( + val jobNumber: Int, + val dialogNumber: Int, + val bank: BankData, + val account: AccountData? +) \ No newline at end of file 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 8213ab49..a7bf63a0 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 @@ -7,6 +7,7 @@ import net.dankito.utils.multiplatform.log.Logger import net.dankito.utils.multiplatform.log.LoggerFactory import net.dankito.utils.multiplatform.Date import net.dankito.utils.multiplatform.StackTraceHelper +import net.dankito.utils.multiplatform.StringHelper import net.dankito.utils.multiplatform.getInnerException import kotlin.reflect.KClass @@ -27,37 +28,60 @@ open class MessageLogCollector { // in either case remove sensitive data after response is parsed as otherwise some information like account holder name and accounts may is not set yet on BankData open val messageLogWithoutSensitiveData: List - get() = messageLog.map { MessageLogEntry(safelyRemoveSensitiveDataFromMessage(it.message, it.bank), it.type, it.time, it.bank) } + get() = messageLog.map { MessageLogEntry(it.type, safelyRemoveSensitiveDataFromMessage(it.message, it.context.bank), it.time, it.context) } protected open val stackTraceHelper = StackTraceHelper() - open fun addMessageLog(bank: BankData, type: MessageLogEntryType, message: String) { + open fun addMessageLog(type: MessageLogEntryType, message: String, context: MessageContext) { val timeStamp = Date() val prettyPrintMessage = prettyPrintHbciMessage(message) - messageLog.add(MessageLogEntry(prettyPrintMessage, type, timeStamp, bank)) + messageLog.add(MessageLogEntry(type, prettyPrintMessage, timeStamp, context)) - log.debug { "${if (type == MessageLogEntryType.Sent) "[${bank.bankCode}-${bank.customerId}] Sending" else "Received"} message:\r\n" + prettyPrintMessage } - } - - protected open fun prettyPrintHbciMessage(message: String): String { - return message.replace("'", "'\r\n") + val messageTrace = createMessageTraceString(type, context) + log.debug { "$messageTrace\r\n$prettyPrintMessage" } } - open fun logError(loggingClass: KClass<*>, bank: BankData, message: String, e: Exception? = null) { + open fun logError(loggingClass: KClass<*>, message: String, context: MessageContext, e: Exception? = null) { + val type = MessageLogEntryType.Error + val messageTrace = createMessageTraceString(type, context) + " " + if (e != null) { - getLogger(loggingClass).error(e) { message } + getLogger(loggingClass).error(e) { messageTrace + message } } else { - getLogger(loggingClass).error(message) + getLogger(loggingClass).error(messageTrace + message) } val errorStackTrace = if (e != null) "\r\n" + getStackTrace(e) else "" - // TODO: what to do when bank is not set? - messageLog.add(MessageLogEntry(message + errorStackTrace, MessageLogEntryType.Error, Date(), bank)) + messageLog.add(MessageLogEntry(type, message + errorStackTrace, Date(), context)) + } + + + protected open fun createMessageTraceString(type: MessageLogEntryType, context: MessageContext): String { + return "${twoDigits(context.jobNumber)}_${twoDigits(context.dialogNumber)}_" + + "${context.bank.bankCode}_${context.bank.customerId}" + + "${ context.account?.let { "_${it.accountIdentifier}" } ?: "" } " + + "${getTypeString(type)}:" + } + + protected open fun twoDigits(number: Int): String { + return StringHelper.format("%02d", number) + } + + protected open fun getTypeString(type: MessageLogEntryType): String { + return when (type) { + MessageLogEntryType.Sent -> "Sending message" + MessageLogEntryType.Received -> "Received message" + MessageLogEntryType.Error -> "Error" + } + } + + protected open fun prettyPrintHbciMessage(message: String): String { + return message.replace("'", "'\r\n") } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/DialogContext.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/DialogContext.kt index 1cd20435..55e1c50a 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/DialogContext.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/DialogContext.kt @@ -6,14 +6,9 @@ import net.dankito.banking.fints.response.BankResponse open class DialogContext( - val closeDialog: Boolean = true, - var abortIfTanIsRequired: Boolean = false, - var currentMessage: MessageBuilderResult? = null, - var dialogId: String = InitialDialogId, - var response: BankResponse? = null, - var didBankCloseDialog: Boolean = false, - var previousMessageInDialog: MessageBuilderResult? = null, // for PinTan almost always the case except for getting a user's TAN methods - var chunkedResponseHandler: ((BankResponse) -> Unit)? = null + open val closeDialog: Boolean = true, + open var dialogId: String = InitialDialogId, + open var chunkedResponseHandler: ((BankResponse) -> Unit)? = null ) { companion object { @@ -22,9 +17,22 @@ open class DialogContext( const val InitialMessageNumber = 0 } + open var currentMessage: MessageBuilderResult? = null + protected set + + open var previousMessageInDialog: MessageBuilderResult? = null + protected set + open var messageNumber: Int = InitialMessageNumber protected set + open var abortIfTanIsRequired: Boolean = false + + open var response: BankResponse? = null + + open var didBankCloseDialog: Boolean = false + + open fun increaseMessageNumber() { messageNumber++ } diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/JobContext.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/JobContext.kt index 1a9055e2..d8b815be 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/JobContext.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/JobContext.kt @@ -2,6 +2,7 @@ package net.dankito.banking.fints.model import net.dankito.banking.fints.callback.FinTsClientCallback import net.dankito.banking.fints.log.IMessageLogAppender +import net.dankito.banking.fints.log.MessageContext import net.dankito.banking.fints.log.MessageLogCollector import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens import net.dankito.banking.fints.response.BankResponse @@ -23,6 +24,10 @@ open class JobContext( protected open val messageLogCollector: MessageLogCollector = MessageLogCollector() ) : MessageBaseData(bank, product), IMessageLogAppender { + companion object { + private var JobCount = 0 // this is not thread safe so job number may not be 100 % accurate + } + protected open val _dialogs = mutableListOf() @@ -39,10 +44,14 @@ open class JobContext( get() = ArrayList(_dialogs) // create a copy + protected open val jobNumber: Int = ++JobCount + + open fun startNewDialog(closeDialog: Boolean = true, dialogId: String = DialogContext.InitialDialogId, versionOfSecurityProcedure: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.Version_2, chunkedResponseHandler: ((BankResponse) -> Unit)? = null) : DialogContext { - val newDialogContext = DialogContext(closeDialog, dialogId = dialogId, chunkedResponseHandler = chunkedResponseHandler) + + val newDialogContext = DialogContext(closeDialog, dialogId, chunkedResponseHandler) this.versionOfSecurityProcedure = versionOfSecurityProcedure @@ -55,11 +64,15 @@ open class JobContext( open fun addMessageLog(type: MessageLogEntryType, message: String) { - messageLogCollector.addMessageLog(bank, type, message) + messageLogCollector.addMessageLog(type, message, createMessageContext()) } override fun logError(loggingClass: KClass<*>, message: String, e: Exception?) { - messageLogCollector.logError(loggingClass, bank, message, e) + messageLogCollector.logError(loggingClass, message, createMessageContext(), e) + } + + protected open fun createMessageContext(): MessageContext { + return MessageContext(jobNumber, dialog.messageNumber, bank, account) } } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageBaseData.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageBaseData.kt index 4f23b99f..ad329ee2 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageBaseData.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageBaseData.kt @@ -8,7 +8,7 @@ open class MessageBaseData( open val product: ProductData ) { - open var versionOfSecurityProcedure: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.PinTanDefaultVersion + open var versionOfSecurityProcedure: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.PinTanDefaultVersion // for PinTan almost always the case except for getting a user's TAN methods protected set } \ No newline at end of file diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageLogEntry.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageLogEntry.kt index 8ba02beb..6d1dfeea 100644 --- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageLogEntry.kt +++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/model/MessageLogEntry.kt @@ -1,13 +1,14 @@ package net.dankito.banking.fints.model +import net.dankito.banking.fints.log.MessageContext import net.dankito.utils.multiplatform.Date open class MessageLogEntry( - open val message: String, open val type: MessageLogEntryType, + open val message: String, open val time: Date, - open val bank: BankData? + open val context: MessageContext ) { override fun toString(): String { diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/MessageLogEntry.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/MessageLogEntry.kt index 3e0d0850..55bcd415 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/MessageLogEntry.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/MessageLogEntry.kt @@ -7,7 +7,10 @@ open class MessageLogEntry( open val message: String, open val type: MessageLogEntryType, open val time: Date, - open val bank: TypedBankData + open val jobNumber: Int, + open val dialogNumber: Int, + open val bank: TypedBankData, + open val account: TypedBankAccount? ) { override fun toString(): String { diff --git a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt index 08d1e4f2..1097047e 100644 --- a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt +++ b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/fints4kBankingClient.kt @@ -215,7 +215,8 @@ open class fints4kBankingClient( protected open fun saveData(response: FinTsClientResponse) { try { _messageLogWithoutSensitiveData.addAll(response.messageLogWithoutSensitiveData - .map { MessageLogEntry(it.message, map(it.type), it.time, bank) }) + .map { MessageLogEntry(it.message, map(it.type), it.time, it.context.jobNumber, + it.context.dialogNumber, bank, it.context.account?.let { mapper.findMatchingAccount(bank, it) } ) }) // TODO: fix that real (child) class get serialized and re-enable again // val clientDataFile = getFints4kClientDataFile(fintsBank.bankCode, fintsBank.customerId)