// Custom log interceptor for financial data
class FinancialDataInterceptor : LogInterceptor {
override fun intercept(level: LogLevel, message: String, data: Any?): Boolean {
// Mask account numbers
if (data is Map<*, *> && data.containsKey("accountNumber")) {
val maskedData = data.toMutableMap()
val accountNumber = maskedData["accountNumber"]?.toString() ?: ""
if (accountNumber.length > 4) {
maskedData["accountNumber"] = "****" + accountNumber.takeLast(4)
}
// Log with masked data
Logger.log(level, message, maskedData)
return true // Handled this log
}
// Also mask any account numbers in the message itself
if (message.contains(Regex("\\b\\d{10,}\\b"))) {
val maskedMessage = message.replace(
Regex("\\b(\\d{6})\\d+\\b"),
{ matchResult -> "${matchResult.groupValues[1]}****" }
)
Logger.log(level, maskedMessage, data)
return true
}
return false // Continue with normal logging
}
}
// Configure logging for financial transactions
Platymap.configureLogging {
level(LogLevel.INFO)
includeDataInLogs(false) // Don't include sensitive data by default
logToFile("/var/log/platymap/financial-transactions.log")
addInterceptor(FinancialDataInterceptor())
}
// Define validation with logging
val transactionValidator = ValidationDsl.preValidate {
info("Starting transaction validation")
validate("transaction.amount")
.required()
.min(0.01)
.debug("Validating transaction amount")
.end()
validate("transaction.currency")
.required()
.allowedValues("USD", "EUR", "GBP", "JPY")
.end()
validate("transaction.sourceAccount")
.required()
.custom({ account ->
// Log with care to avoid exposing full account number
debug("Validating source account: ${account.toString().takeLast(4)}")
account.toString().length >= 10 // Simple validation
}, "Invalid source account")
.end()
validate("transaction.destinationAccount")
.required()
.custom({ account ->
debug("Validating destination account: ${account.toString().takeLast(4)}")
account.toString().length >= 10
}, "Invalid destination account")
.end()
info("Transaction validation complete")
}
// Create mapping with logging
val transactionMapping = Platymap.flow("transaction")
.withFormat(FormatType.JSON)
.to("processedTransaction")
.withFormat(FormatType.JSON)
// Use pre-validation
.withPreValidation {
info("Validating financial transaction")
validate("transaction.amount").required().min(0.01).end()
validate("transaction.currency").required().end()
// More validations...
}
// Logging transaction initiation
.info("Starting financial transaction processing")
.logData("Processing transaction",
"transaction.id",
"transaction.amount",
"transaction.currency")
// Basic transaction mapping
.map("transaction.id").to("processedTransaction.transactionId").end()
.map("transaction.timestamp").to("processedTransaction.processedAt").end()
// Amount with currency formatting
.map("transaction.amount")
.transform { amount ->
debug("Processing amount: $amount")
(amount as Number).toDouble()
}
.to("processedTransaction.amount")
.end()
.map("transaction.currency").to("processedTransaction.currency").end()
// Source account with masked logging
.map("transaction.sourceAccount")
.transform { account ->
val accStr = account.toString()
// Deliberately only log last 4 digits
debug("Processing source account: ****${accStr.takeLast(4)}")
accStr
}
.to("processedTransaction.source")
.end()
// Destination account with masked logging
.map("transaction.destinationAccount")
.transform { account ->
val accStr = account.toString()
debug("Processing destination account: ****${accStr.takeLast(4)}")
accStr
}
.to("processedTransaction.destination")
.end()
// Transaction status
.map("'PENDING'").to("processedTransaction.status").end()
// Fee calculation with logging
.map("transaction.amount")
.transform { amount ->
val amountValue = (amount as Number).toDouble()
val fee = amountValue * 0.01 // 1% fee
info("Calculated fee: $fee")
fee
}
.to("processedTransaction.fee")
.end()
// Completion logging
.info("Financial transaction processing complete")
.build()
// Execute with logging and error handling
try {
val result = transactionMapping.executeToJson(transactionJson)
Logger.info("Transaction processed successfully", mapOf(
"transactionId" to extractTransactionId(result)
))
} catch (e: ValidationException) {
Logger.error("Transaction validation failed", mapOf(
"errors" to e.errors.map { "${it.path}: ${it.message}" }
))
} catch (e: Exception) {
Logger.error("Transaction processing failed: ${e.message}")
}