This document establishes the standardized logging patterns used in FPXController and RevPayController to ensure consistent logging across all payment processing modules in the Axaipay backend.
All payment-related logs follow a structured format that includes:
- Audit Tag: Clear identification of the payment system (e.g.,
[FPX_AUDIT],[REVPAY_AUDIT]) - Transaction Reference: Always include transaction ID or reference number for traceability
- Endpoint/Action: Clear identification of the operation being performed
- Key Business Data: Include relevant payment details for audit purposes
[SYSTEM_AUDIT] [TXN:{transactionId}] [OPERATION] {message} - Key: Value, Key: Value
Components:
SYSTEM_AUDIT: Payment system identifier (FPX_AUDIT, REVPAY_AUDIT, etc.)TXN:{transactionId}: Transaction identifier for traceabilityREF:{referenceNumber}: Alternative reference identifier when TXN not availableOPERATION: Business operation being performed (DIRECT_ENDPOINT, BACKEND_ENDPOINT, etc.)- Message and key-value pairs for business context
Used for normal business operations and successful processing:
log.info("[FPX_AUDIT] [TXN:{}] [DIRECT_ENDPOINT] Direct callback received - Message Type: {}, Auth Code: {}, Amount: {}",
fpxModel.getFpx_sellerOrderNo(), fpxModel.getFpx_msgType(), fpxModel.getFpx_debitAuthCode(), fpxModel.getFpx_txnAmount());
log.info("[REVPAY_AUDIT] [REF:{}] [BACKEND_ENDPOINT] Backend callback received - Response Code: {}, Amount: {}",
revPayResultModel.getReference_Number(), revPayResultModel.getResponse_Code(), revPayResultModel.getAmount());Used for detailed technical information during development:
log.debug("[REVPAY_AUDIT] [REF:{}] Looking up transaction by reference number", transactionId);
log.debug("[FPX_AUDIT] [BANKLIST] Retrieving bank list for payment type: {}", paymentType);Used for concerning but non-fatal conditions:
log.warn("[FPX_AUDIT] [TXN:{}] [DIRECT_CALLBACK] OVERWRITE PREVENTED - Duplicate auth code {} on PAID transaction",
currentSalesTransaction.getTransactionId(), fpxModel.getFpx_debitAuthCode().trim());
log.warn("[FPX_AUDIT] [TXN:{}] [DIRECT_CALLBACK] BLACKLISTED CUSTOMER DETECTED - Buyer: {}",
fpxModel.getFpx_sellerOrderNo(), fpxModel.getFpx_buyerName());Used for errors and security violations:
log.error("[FPX_AUDIT] [TXN:{}] [DIRECT_ENDPOINT] SECURITY VIOLATION - Invalid FPX server request from IP: {}",
fpxModel.getFpx_sellerOrderNo(), fpxSecurityValidator.getClientIP(request));
log.error("[REVPAY_AUDIT] [TXN:{}] [BACKEND_ENDPOINT] SIGNATURE VALIDATION FAILED - Response Code: {}",
currentSalesTransaction.getTransactionId(), revPayResultModel.getResponse_Code());Pattern: [SYSTEM_AUDIT] [TXN:{id}] [DIRECT_ENDPOINT|BACKEND_ENDPOINT] {action} - {context}
Examples:
// Receiving callback
log.info("[FPX_AUDIT] [TXN:{}] [DIRECT_ENDPOINT] Direct callback received - Message Type: {}, Auth Code: {}", ...);
log.info("[REVPAY_AUDIT] [REF:{}] [BACKEND_ENDPOINT] Backend callback received - Response Code: {}, Amount: {}", ...);
// Processing result
log.info("[FPX_AUDIT] [TXN:{}] [DIRECT_CALLBACK] Processing transaction result - Current Status: {}, Auth Code: {}", ...);
log.info("[REVPAY_AUDIT] [TXN:{}] [BACKEND_ENDPOINT] Backend callback processed successfully - Response: {}", ...);Pattern: [SYSTEM_AUDIT] [TXN:{id}] [INDIRECT_ENDPOINT|REDIRECT_ENDPOINT] {action} - {context}
Examples:
log.info("[FPX_AUDIT] [TXN:{}] [INDIRECT_ENDPOINT] Indirect callback received - Message Type: {}, Auth Code: {}", ...);
log.info("[REVPAY_AUDIT] [REF:{}] [REDIRECT_ENDPOINT] Redirect callback received - Response Code: {}, Amount: {}", ...);Pattern: [SYSTEM_AUDIT] [REF:{ref}|TXN:{id}] TRANSACTION {result} - {context}
Examples:
log.error("[FPX_AUDIT] [TXN:{}] [DIRECT_CALLBACK] TRANSACTION NOT FOUND - Seller order number does not exist", ...);
log.error("[REVPAY_AUDIT] [REF:{}] TRANSACTION NOT FOUND - Reference number does not exist", transactionId);
log.debug("[REVPAY_AUDIT] [TXN:{}] [REF:{}] Transaction found - Status: {}", ...);Pattern: [SYSTEM_AUDIT] [TXN:{id}] [OPERATION] VALIDATION FAILED - {details}
Examples:
log.error("[FPX_AUDIT] [INDIRECT_ENDPOINT] VALIDATION FAILED - Missing required parameters: fpxModel={}, sellerOrderNo={}", ...);
log.error("[REVPAY_AUDIT] [TXN:{}] [BACKEND_ENDPOINT] SIGNATURE VALIDATION FAILED - Response Code: {}", ...);Pattern: [SYSTEM_AUDIT] [TXN:{id}] [OPERATION] SECURITY VIOLATION - {violation_type}: {details}
Examples:
log.error("[FPX_AUDIT] [TXN:{}] [INDIRECT_ENDPOINT] SECURITY VIOLATION - Invalid origin: {}, IP: {}", ...);
log.error("[FPX_AUDIT] [TXN:{}] [DIRECT_ENDPOINT] SECURITY VIOLATION - Invalid FPX server request from IP: {}", ...);Both controllers integrate HTTP request logging using utility methods:
// FPX Controller uses
logHttpSync(log, request, true);
// RevPay Controller uses
logHttpStructured(logger, request, true);Rule: Always call HTTP logging utilities immediately after the initial endpoint log entry.
- Transaction ID or Reference Number
- Operation type (endpoint name/action)
- Response/auth codes where applicable
- FPX: Message Type, Auth Code, Amount, Bank ID, Buyer Name
- RevPay: Response Code, Amount, Reference Number
- General: Transaction Status, Current Status
- IP Address
- Origin/Host information
- Validation failure reasons
- Blacklist detection details
When implementing logging in new payment controllers:
- Use SLF4J with
@Slf4jorLoggerFactory.getLogger() - Define consistent audit tag (e.g.,
[NEWPAYMENT_AUDIT]) - Import and use HTTP logging utilities
- Log entry point with transaction reference and key business data
- Call HTTP logging utility after initial log
- Log processing steps with intermediate status
- Log final result with success/failure indication
- Log all validation failures with ERROR level
- Log security violations with ERROR level and IP context
- Log business warnings (duplicates, blacklists) with WARN level
- Include full context in error logs (transaction ID, operation, failure reason)
- Log transaction lookup attempts
- Log transaction status changes
- Log duplicate transaction prevention
- Include transaction status in logs where relevant
- Log signature validation attempts and failures
- Log origin/IP validation for security
- Log blacklist checks and violations
- Include security context (IP, origin, validation type)
❌ Inconsistent Audit Tags
log.info("Processing FPX transaction {}"); // Missing audit tag❌ Missing Transaction Context
log.info("[FPX_AUDIT] Direct callback received"); // Missing transaction ID❌ Insufficient Business Context
log.info("[FPX_AUDIT] [TXN:{}] Processing", txnId); // Missing operation details❌ Mixing Log Levels Inappropriately
log.error("[FPX_AUDIT] [TXN:{}] Transaction processed successfully", txnId); // Should be INFO❌ Incomplete Error Context
log.error("Validation failed"); // Missing transaction ID, operation, and failure reason@Controller
@RequestMapping("/payments/newpayment")
@Slf4j
public class NewPaymentController {
@PostMapping("/backend-result")
public ResponseEntity<String> handleBackendCallback(@ModelAttribute NewPaymentModel model,
HttpServletRequest request) {
// 1. Initial entry log with business context
log.info("[NEWPAYMENT_AUDIT] [REF:{}] [BACKEND_ENDPOINT] Backend callback received - Status: {}, Amount: {}",
model.getReferenceNumber(), model.getStatus(), model.getAmount());
// 2. HTTP request logging
logHttpStructured(log, request, true);
try {
// 3. Transaction lookup with logging
SalesTransaction transaction = getTransactionOrThrow(model.getReferenceNumber());
// 4. Validation with logging
if (!validator.validateSignature(transaction, model)) {
log.error("[NEWPAYMENT_AUDIT] [TXN:{}] [BACKEND_ENDPOINT] SIGNATURE VALIDATION FAILED - Status: {}",
transaction.getTransactionId(), model.getStatus());
return ResponseEntity.badRequest().body("Signature mismatch");
}
// 5. Processing with status logging
log.info("[NEWPAYMENT_AUDIT] [TXN:{}] [BACKEND_ENDPOINT] Processing callback - Current Status: {}",
transaction.getTransactionId(), transaction.getStatusId());
ProcessingResult result = processor.processCallback(transaction, model);
// 6. Final result logging
log.info("[NEWPAYMENT_AUDIT] [TXN:{}] [BACKEND_ENDPOINT] Callback processed successfully - Result: {}",
transaction.getTransactionId(), result.getStatus());
return ResponseEntity.ok("SUCCESS");
} catch (Exception e) {
log.error("[NEWPAYMENT_AUDIT] [REF:{}] [BACKEND_ENDPOINT] ERROR - Processing failed: {}",
model.getReferenceNumber(), e.getMessage(), e);
return ResponseEntity.badRequest().body("ERROR");
}
}
private SalesTransaction getTransactionOrThrow(String referenceNumber) {
log.debug("[NEWPAYMENT_AUDIT] [REF:{}] Looking up transaction", referenceNumber);
SalesTransaction transaction = salesTransactionService.getByTransactionId(referenceNumber);
if (transaction == null) {
log.error("[NEWPAYMENT_AUDIT] [REF:{}] TRANSACTION NOT FOUND", referenceNumber);
throw ServiceExceptionHelper.error(PaymentErrorCodes.SALES_TRANSACTION_NOT_FOUND, referenceNumber);
}
log.debug("[NEWPAYMENT_AUDIT] [TXN:{}] [REF:{}] Transaction found - Status: {}",
transaction.getTransactionId(), referenceNumber, transaction.getStatusId());
return transaction;
}
}This logging standard ensures consistent audit trails, proper error tracking, and sufficient business context for debugging and compliance requirements across all payment processing modules.