The Logs & Monitoring system provides comprehensive monitoring, debugging, and audit capabilities for the BookNow platform. Designed with developer-first principles and inspired by Stripe's logging architecture, it enables real-time visibility into user actions, API calls, system events, and errors across booking and payment flows.
This documentation covers the complete logging infrastructure, from implementation patterns to troubleshooting workflows.
Quick Start
Accessing the Log Viewer
The Log Viewer is available at /staff/log-viewer and provides both dashboard and detailed log views:
- Dashboard View: System statistics, recent activity, and session overview
- Detail View: Filtered logs with full request/response data
- Search Interface: Find logs by booking ID, session ID, or specific criteria
URL Parameters for Direct Access
/staff/log-viewer?booking_id=a03XX0000001234/staff/log-viewer?session_id=ABC123/staff/log-viewer?log_id=a0XXX0000012345Architecture Overview
Core Components
The EPOS logging system consists of several integrated components:
| Component | Purpose | Location |
|---|---|---|
| EposLogViewer LWC | User interface and dashboard | /lwc/eposLogViewer/ |
| EposLogger Utility | Client-side logging helper | /lwc/eposLogger/ |
| EposLogProcessor | Server-side processing | /classes/EposLogProcessor.cls |
| Log Cleanup System | Automated retention management | /classes/EposLogCleanup*.cls |
Data Model
The Bnow__Epos_Processing_Log__c custom object captures comprehensive audit data:
// Core identificationBnow__Method_Name__c // Function/method calledBnow__Component_Name__c // Source component (EPOS, MAF, etc.)Bnow__Session_Id__c // Links related user actionsBnow__Booking__c // Related booking record
// Request/Response dataBnow__Request_Parameters__c // Input JSON (up to 131KB)Bnow__Response_Body__c // Output JSON (up to 131KB)Bnow__Http_Status_Code__c // HTTP-style status (200, 400, 500)
// Performance and timingBnow__Processing_Duration__c // Execution time (milliseconds)Bnow__Timestamp__c // When action occurredBnow__Processing_Stage__c // Current processing phase
// Management and retentionBnow__User_Action__c // Human-readable descriptionBnow__Retain_Log__c // Prevent automatic cleanupBnow__Error_Details__c // Detailed error informationLogging Implementation
Client-Side Logging
Using the EposLogger Utility
import { EposLogger } from 'c/eposLogger';
// Standard action loggingawait EposLogger.logEposAction( 'eposCart', // Component name 'addProduct', // Method name 'User added product to cart', // Human description this.sessionId, // Session ID this.bookingId, // Booking ID (optional) { product_id: 'P123', qty: 2 } // Additional data);
// Fire-and-forget logging (recommended for performance)EposLogger.logEposActionAsync( this.constructor.name, 'handlePayment', 'Payment submitted via terminal', this.sessionId, this.bookingId, paymentData);Specialized Logging Methods
// Log quantity adjustmentsEposLogger.logQuantityAdjustment( 'eposCart', this.sessionId, 'Product123', 2, // old quantity 5, // new quantity 'User increased quantity');
// Log booking option changesEposLogger.logBookingOptionChange( 'eposBookingOptions', this.sessionId, 'time_slot', '14:00', // old value '15:30', // new value 'Customer changed appointment time');
// Log user actions with custom dataEposLogger.logUserAction( 'eposPayment', 'selectPaymentMethod', 'Customer selected card payment', this.sessionId, this.bookingId, { payment_method: 'card', terminal_id: 'TRM001' });Server-Side Integration
Automatic Logging in Apex
The system automatically captures logs from key EPOS controller methods:
// EposLwcCtrl.handleFunction() automatically logs:// - Request parameters and response data// - Processing duration and status codes// - Component name and session context// - Error details for failed operations
// Manual logging in custom methodsEposLogProcessor.processLogAsync(new Bnow__Epos_Processing_Log__c( Bnow__Component_Name__c = 'CustomController', Bnow__Method_Name__c = 'processSpecialOrder', Bnow__User_Action__c = 'Processing special dietary requirement', Bnow__Session_Id__c = sessionId, Bnow__Booking__c = bookingId, Bnow__Request_Parameters__c = JSON.serialize(orderData), Bnow__Http_Status_Code__c = 200, Bnow__Timestamp__c = DateTime.now()));Log Viewer Interface
Dashboard Mode
The dashboard provides system-wide visibility:
- Activity Statistics: 24-hour and 7-day request volumes
- Error Rate Monitoring: Percentage of failed operations
- Recent Sessions: Clickable list of active user sessions
- Top Methods: Most frequently called functions
- Performance Metrics: Average response times and error trends
Detail Mode
Filter and examine specific logs:
- Advanced Search: By booking ID, session ID, status, or method name
- Timeline View: Chronological display of related events
- JSON Viewer: Syntax-highlighted, expandable request/response data
- Status Indicators: Color-coded HTTP status badges
- Copy Functions: One-click ID copying for collaboration
Navigation and Filtering
Search Interface
// URL parameter examples?booking_id=BKN-1234567890 // Find logs for specific booking?session_id=ABC123456789 // View complete user session?status=500 // Show only server errors?method=submitPayment // Filter to payment operations?search=stripe // Text search across all fieldsCopy-to-Clipboard Functionality
The interface provides one-click copying for:
- Booking IDs: Share with support teams
- Session IDs: Track user journeys
- Log IDs: Reference specific events
- JSON Data: Debug request/response payloads
Error Monitoring & Debugging
Error Classification
Logs are categorized by HTTP-style status codes:
| Status Range | Type | Description | Retention |
|---|---|---|---|
| 200-299 | Success | Normal operations | 7 days |
| 400-499 | Client Error | Invalid requests, validation failures | 30 days |
| 500-599 | Server Error | System failures, exceptions | Permanent |
Common Debug Scenarios
Payment Failures
// Search for payment-related errorsMethod Name: submitPaymentStatus: 500Time Range: Last 24 hours
// Typical error indicators:// - Gateway timeouts (status 504)// - Invalid card data (status 400)// - Insufficient funds (status 402)// - Terminal connectivity (status 503)Booking Flow Issues
// Trace complete booking creationSession ID: ABC123456789
// Follow the journey:// 1. fetchProducts (load available items)// 2. fetchAvailability (check time slots)// 3. handleReserve (reserve assets)// 4. submitPayment (process payment)Performance Investigation
// Identify slow operationsProcessing Duration: > 5000msMethod Names: submitPayment, fetchAvailability, handleReserve
// Common performance bottlenecks:// - External API calls (payment gateways)// - Complex availability calculations// - Database query optimization neededTroubleshooting Workflows
Step 1: Identify the Issue
- Locate the failing operation using booking ID or session ID
- Check the error status and review error details
- Examine request parameters for invalid data
- Review response data for specific error messages
Step 2: Trace the User Journey
- Find the session ID from the failing operation
- Filter logs by session to see the complete sequence
- Identify where the flow diverged from expected behavior
- Check preceding operations for context clues
Step 3: Reproduce and Fix
- Copy request parameters from the failing log
- Test with similar data in a development environment
- Implement fixes addressing the root cause
- Verify resolution by monitoring subsequent logs
Data Retention & Cleanup
Automatic Cleanup System
The system includes intelligent data retention:
// Default retention periodsNormal Logs: 7 daysError Logs: 30 daysCritical Events: PermanentAudit Trails: Permanent
// Emergency cleanup thresholdsTotal Logs: > 1,000,000 recordsOld Logs: > 500,000 records older than 7 daysRecent Spike: > 50,000 logs in 24 hoursManual Cleanup Operations
Emergency Cleanup
// Immediate cleanup with 1-day retentionEposLogCleanupScheduler.emergencyCleanup();
// Aggressive cleanup with 3-day retentionEposLogCleanupScheduler.aggressiveCleanup();
// Custom retention periodEposLogCleanupScheduler.manualCleanup(5); // 5 daysVolume Monitoring
// Check current log volumeMap<String, Integer> report = EposLogCleanupScheduler.getLogVolumeReport();
// Returns:// Last_24_Hours: 1,250// Last_3_Days: 4,800// Last_7_Days: 12,500// Older_Than_7_Days: 45,000// Total_Retained_Logs: 2,100// Total_All_Logs: 62,650
// Check if emergency cleanup neededBoolean emergency = EposLogCleanupScheduler.isEmergencyCleanupNeeded();Protected Log Types
The following logs are never automatically deleted:
- System Maintenance: Cleanup audit trails
- Orphan Product Detection: Critical business errors
- System Error Detection: Platform failures
- Manual Retention: Logs marked with
Retain_Log__c = true
Performance Optimization
Logging Best Practices
Client-Side Performance
// ✅ Recommended: Async fire-and-forgetEposLogger.logEposActionAsync(componentName, method, action, sessionId);
// ❌ Avoid: Synchronous logging in tight loopsfor(let product of products) { await EposLogger.logEposAction(...); // Blocks UI}
// ✅ Better: Batch operationslet batchData = products.map(p => ({ product: p, action: 'added' }));EposLogger.logEposActionAsync('eposCart', 'batchAdd', 'Added multiple products', sessionId, bookingId, batchData);Server-Side Efficiency
// ✅ Efficient: Use async processingEposLogProcessor.processLogAsync(logData);
// ✅ Smart retention: Auto-mark critical logslogData.Bnow__Retain_Log__c = (logData.Bnow__Http_Status_Code__c >= 400);
// ❌ Avoid: Synchronous DML in tight loopsfor(LogData data : batchData) { insert logRecord; // Creates transaction bottlenecks}Data Volume Management
Query Optimization
The system uses intelligent query limits:
// Dashboard queries (last 7 days, max 5000 records)SELECT Id, Bnow__Method_Name__c, Bnow__Http_Status_Code__c, Bnow__Timestamp__cFROM Bnow__Epos_Processing_Log__cWHERE Bnow__Timestamp__c >= :sevenDaysAgoORDER BY Bnow__Timestamp__c DESCLIMIT 5000
// Detail queries (filtered by booking/session)SELECT * FROM Bnow__Epos_Processing_Log__cWHERE Bnow__Booking__c = :bookingIdOR Bnow__Session_Id__c = :sessionIdORDER BY Bnow__Timestamp__c ASCMemory Management
- JSON Truncation: Request/response data limited to 131KB per field
- Paginated Loading: UI loads logs in manageable chunks
- Garbage Collection: Automatic cleanup prevents storage bloat
Integration Patterns
Component Integration
Standard LWC Integration
// Import the logging utilityimport { EposLogger } from 'c/eposLogger';
export default class MyEposComponent extends LightningElement { @track sessionId = 'session_' + Date.now();
async handleUserAction() { try { // Perform business logic let result = await this.processOrder();
// Log successful action EposLogger.logEposActionAsync( this.constructor.name, 'processOrder', 'Order processed successfully', this.sessionId, this.bookingId, { order_id: result.id, total: result.amount } );
} catch (error) { // Log error with details EposLogger.logEposActionAsync( this.constructor.name, 'processOrder', 'Order processing failed: ' + error.message, this.sessionId, this.bookingId, { error: error.message, stack: error.stack } ); } }}Apex Controller Integration
public with sharing class MyEposController {
@AuraEnabled public static ResponseWrapper processBookingData(String requestData) { String sessionId = UserInfo.getSessionId().substring(0, 15); DateTime startTime = DateTime.now();
try { // Process business logic BookingData result = processBusinessLogic(requestData);
// Log successful processing EposLogProcessor.processLogAsync(new Bnow__Epos_Processing_Log__c( Bnow__Component_Name__c = 'MyEposController', Bnow__Method_Name__c = 'processBookingData', Bnow__User_Action__c = 'Booking data processed successfully', Bnow__Session_Id__c = sessionId, Bnow__Request_Parameters__c = requestData, Bnow__Response_Body__c = JSON.serialize(result), Bnow__Http_Status_Code__c = 200, Bnow__Processing_Duration__c = DateTime.now().getTime() - startTime.getTime(), Bnow__Timestamp__c = DateTime.now() ));
return result;
} catch (Exception e) { // Log error with full context EposLogProcessor.processLogAsync(new Bnow__Epos_Processing_Log__c( Bnow__Component_Name__c = 'MyEposController', Bnow__Method_Name__c = 'processBookingData', Bnow__User_Action__c = 'Booking processing failed', Bnow__Session_Id__c = sessionId, Bnow__Request_Parameters__c = requestData, Bnow__Http_Status_Code__c = 500, Bnow__Error_Details__c = e.getMessage() + '\n' + e.getStackTraceString(), Bnow__Processing_Duration__c = DateTime.now().getTime() - startTime.getTime(), Bnow__Timestamp__c = DateTime.now(), Bnow__Retain_Log__c = true // Keep error logs ));
throw e; } }}Event Flow Integration
Booking Journey Tracking
// Track complete booking flowclass EposBookingFlow { constructor() { this.sessionId = 'booking_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); this.bookingId = null; }
async step1_LoadProducts() { EposLogger.logEposActionAsync('EposBookingFlow', 'loadProducts', 'Loading available products', this.sessionId); // ... business logic }
async step2_CheckAvailability(selectedDate) { EposLogger.logEposActionAsync('EposBookingFlow', 'checkAvailability', 'Checking availability for ' + selectedDate, this.sessionId, null, {date: selectedDate}); // ... business logic }
async step3_CreateBooking(bookingData) { let result = await this.createBooking(bookingData); this.bookingId = result.bookingId;
EposLogger.logEposActionAsync('EposBookingFlow', 'createBooking', 'Booking created successfully', this.sessionId, this.bookingId, bookingData); return result; }
async step4_ProcessPayment(paymentData) { EposLogger.logEposActionAsync('EposBookingFlow', 'processPayment', 'Processing payment', this.sessionId, this.bookingId, paymentData); // ... payment logic }}Advanced Features
Custom Dashboards
Creating Custom Log Views
// Custom dashboard componentexport default class CustomEposMonitor extends LightningElement { @wire(getEposLogs, { filters: { method: 'submitPayment', status: '500', hours: 24 } }) paymentErrors;
@wire(getEposLogs, { filters: { component: 'eposCart', action: 'addProduct', hours: 1 } }) recentActivity;}Performance Monitoring
// Custom performance trackingpublic class EposPerformanceMonitor {
public static Map<String, Object> getPerformanceMetrics() { return new Map<String, Object>{ 'avg_response_time' => [SELECT AVG(Bnow__Processing_Duration__c) FROM Bnow__Epos_Processing_Log__c WHERE Bnow__Timestamp__c >= :DateTime.now().addHours(-24)][0].get('expr0'), 'error_rate' => calculateErrorRate(), 'top_slow_methods' => getSlowMethods(), 'session_volume' => getSessionVolume() }; }}Alerting and Notifications
Setting Up Alerts
// Custom alert logicpublic class EposAlertMonitor implements Schedulable {
public void execute(SchedulableContext sc) { // Check error rate Decimal errorRate = calculateHourlyErrorRate(); if (errorRate > 5.0) { sendAlert('High error rate detected: ' + errorRate + '%'); }
// Check response times Double avgResponseTime = getAverageResponseTime(); if (avgResponseTime > 10000) { // 10 seconds sendAlert('Slow response times detected: ' + avgResponseTime + 'ms average'); } }}Troubleshooting Common Issues
Log Viewer Not Loading
- Check User Permissions: Ensure access to
Bnow__Epos_Processing_Log__cobject - Verify Data Exists: Confirm logs are being created by checking recent activity
- Clear Browser Cache: Force refresh the component
- Check Console Errors: Look for JavaScript errors in browser developer tools
Missing Log Data
- Verify Integration: Check that
EposLoggeris imported and used correctly - Check Async Processing: Logs may take a few seconds to appear due to async processing
- Review Filters: Ensure search criteria isn't too restrictive
- Check Retention: Verify logs haven't been automatically cleaned up
Performance Issues
- Limit Date Range: Use shorter time windows for large datasets
- Use Specific Filters: Filter by booking ID or session ID instead of browsing all logs
- Check Volume: Use
getLogVolumeReport()to identify if cleanup is needed - Monitor Resource Usage: Check Salesforce org limits and usage
Related Resources
Last updated: 2025-06-30 | Version: 1.0.0