Skip to content

Instantly share code, notes, and snippets.

@alifhaikal88
Created August 10, 2025 08:14
Show Gist options
  • Select an option

  • Save alifhaikal88/70862b8944cfdda73517196d0386ab1c to your computer and use it in GitHub Desktop.

Select an option

Save alifhaikal88/70862b8944cfdda73517196d0386ab1c to your computer and use it in GitHub Desktop.
Axaipay Backend Logging Standards - Payment Controller Audit Trail Guidelines

Payment Controller Logging Standards

Overview

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.

Core Logging Principles

1. Structured Audit Trail Format

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

2. Standard Log Format Pattern

[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 traceability
  • REF:{referenceNumber}: Alternative reference identifier when TXN not available
  • OPERATION: Business operation being performed (DIRECT_ENDPOINT, BACKEND_ENDPOINT, etc.)
  • Message and key-value pairs for business context

Logging Levels and Usage

INFO Level - Business Operations

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());

DEBUG Level - Technical Details

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);

WARN Level - Business Logic Warnings

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());

ERROR Level - Critical Issues

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());

Endpoint-Specific Patterns

Direct/Backend Callbacks

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: {}", ...);

Redirect/Frontend Callbacks

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: {}", ...);

Transaction Lookups

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: {}", ...);

Validation Failures

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: {}", ...);

Security Violations

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: {}", ...);

Required HTTP Logging Integration

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.

Key Business Data Requirements

Transaction Context (Always Required)

  • Transaction ID or Reference Number
  • Operation type (endpoint name/action)
  • Response/auth codes where applicable

Payment-Specific Data (Include When Available)

  • FPX: Message Type, Auth Code, Amount, Bank ID, Buyer Name
  • RevPay: Response Code, Amount, Reference Number
  • General: Transaction Status, Current Status

Security Context (Include for Security Events)

  • IP Address
  • Origin/Host information
  • Validation failure reasons
  • Blacklist detection details

Implementation Checklist

When implementing logging in new payment controllers:

✅ Basic Setup

  • Use SLF4J with @Slf4j or LoggerFactory.getLogger()
  • Define consistent audit tag (e.g., [NEWPAYMENT_AUDIT])
  • Import and use HTTP logging utilities

✅ Endpoint Logging

  • 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

✅ Error Handling

  • 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)

✅ Transaction Management

  • Log transaction lookup attempts
  • Log transaction status changes
  • Log duplicate transaction prevention
  • Include transaction status in logs where relevant

✅ Security Logging

  • Log signature validation attempts and failures
  • Log origin/IP validation for security
  • Log blacklist checks and violations
  • Include security context (IP, origin, validation type)

Common Anti-Patterns to Avoid

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

Example Implementation Template

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment