Skip to content

Logs & Monitoring

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:

  1. Dashboard View: System statistics, recent activity, and session overview
  2. Detail View: Filtered logs with full request/response data
  3. 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=a0XXX0000012345

Architecture Overview

Core Components

The EPOS logging system consists of several integrated components:

ComponentPurposeLocation
EposLogViewer LWCUser interface and dashboard/lwc/eposLogViewer/
EposLogger UtilityClient-side logging helper/lwc/eposLogger/
EposLogProcessorServer-side processing/classes/EposLogProcessor.cls
Log Cleanup SystemAutomated retention management/classes/EposLogCleanup*.cls

Data Model

The Bnow__Epos_Processing_Log__c custom object captures comprehensive audit data:

// Core identification
Bnow__Method_Name__c // Function/method called
Bnow__Component_Name__c // Source component (EPOS, MAF, etc.)
Bnow__Session_Id__c // Links related user actions
Bnow__Booking__c // Related booking record
// Request/Response data
Bnow__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 timing
Bnow__Processing_Duration__c // Execution time (milliseconds)
Bnow__Timestamp__c // When action occurred
Bnow__Processing_Stage__c // Current processing phase
// Management and retention
Bnow__User_Action__c // Human-readable description
Bnow__Retain_Log__c // Prevent automatic cleanup
Bnow__Error_Details__c // Detailed error information

Logging Implementation

Client-Side Logging

Using the EposLogger Utility

import { EposLogger } from 'c/eposLogger';
// Standard action logging
await 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 adjustments
EposLogger.logQuantityAdjustment(
'eposCart',
this.sessionId,
'Product123',
2, // old quantity
5, // new quantity
'User increased quantity'
);
// Log booking option changes
EposLogger.logBookingOptionChange(
'eposBookingOptions',
this.sessionId,
'time_slot',
'14:00', // old value
'15:30', // new value
'Customer changed appointment time'
);
// Log user actions with custom data
EposLogger.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 methods
EposLogProcessor.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

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 fields

Copy-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 RangeTypeDescriptionRetention
200-299SuccessNormal operations7 days
400-499Client ErrorInvalid requests, validation failures30 days
500-599Server ErrorSystem failures, exceptionsPermanent

Common Debug Scenarios

Payment Failures

// Search for payment-related errors
Method Name: submitPayment
Status: 500
Time 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 creation
Session 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 operations
Processing Duration: > 5000ms
Method Names: submitPayment, fetchAvailability, handleReserve
// Common performance bottlenecks:
// - External API calls (payment gateways)
// - Complex availability calculations
// - Database query optimization needed

Troubleshooting Workflows

Step 1: Identify the Issue

  1. Locate the failing operation using booking ID or session ID
  2. Check the error status and review error details
  3. Examine request parameters for invalid data
  4. Review response data for specific error messages

Step 2: Trace the User Journey

  1. Find the session ID from the failing operation
  2. Filter logs by session to see the complete sequence
  3. Identify where the flow diverged from expected behavior
  4. Check preceding operations for context clues

Step 3: Reproduce and Fix

  1. Copy request parameters from the failing log
  2. Test with similar data in a development environment
  3. Implement fixes addressing the root cause
  4. Verify resolution by monitoring subsequent logs

Data Retention & Cleanup

Automatic Cleanup System

The system includes intelligent data retention:

// Default retention periods
Normal Logs: 7 days
Error Logs: 30 days
Critical Events: Permanent
Audit Trails: Permanent
// Emergency cleanup thresholds
Total Logs: > 1,000,000 records
Old Logs: > 500,000 records older than 7 days
Recent Spike: > 50,000 logs in 24 hours

Manual Cleanup Operations

Emergency Cleanup

// Immediate cleanup with 1-day retention
EposLogCleanupScheduler.emergencyCleanup();
// Aggressive cleanup with 3-day retention
EposLogCleanupScheduler.aggressiveCleanup();
// Custom retention period
EposLogCleanupScheduler.manualCleanup(5); // 5 days

Volume Monitoring

// Check current log volume
Map<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 needed
Boolean 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-forget
EposLogger.logEposActionAsync(componentName, method, action, sessionId);
// ❌ Avoid: Synchronous logging in tight loops
for(let product of products) {
await EposLogger.logEposAction(...); // Blocks UI
}
// ✅ Better: Batch operations
let batchData = products.map(p => ({ product: p, action: 'added' }));
EposLogger.logEposActionAsync('eposCart', 'batchAdd', 'Added multiple products', sessionId, bookingId, batchData);

Server-Side Efficiency

// ✅ Efficient: Use async processing
EposLogProcessor.processLogAsync(logData);
// ✅ Smart retention: Auto-mark critical logs
logData.Bnow__Retain_Log__c = (logData.Bnow__Http_Status_Code__c >= 400);
// ❌ Avoid: Synchronous DML in tight loops
for(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__c
FROM Bnow__Epos_Processing_Log__c
WHERE Bnow__Timestamp__c >= :sevenDaysAgo
ORDER BY Bnow__Timestamp__c DESC
LIMIT 5000
// Detail queries (filtered by booking/session)
SELECT * FROM Bnow__Epos_Processing_Log__c
WHERE Bnow__Booking__c = :bookingId
OR Bnow__Session_Id__c = :sessionId
ORDER BY Bnow__Timestamp__c ASC

Memory 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 utility
import { 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 flow
class 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 component
export 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 tracking
public 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 logic
public 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

  1. Check User Permissions: Ensure access to Bnow__Epos_Processing_Log__c object
  2. Verify Data Exists: Confirm logs are being created by checking recent activity
  3. Clear Browser Cache: Force refresh the component
  4. Check Console Errors: Look for JavaScript errors in browser developer tools

Missing Log Data

  1. Verify Integration: Check that EposLogger is imported and used correctly
  2. Check Async Processing: Logs may take a few seconds to appear due to async processing
  3. Review Filters: Ensure search criteria isn't too restrictive
  4. Check Retention: Verify logs haven't been automatically cleaned up

Performance Issues

  1. Limit Date Range: Use shorter time windows for large datasets
  2. Use Specific Filters: Filter by booking ID or session ID instead of browsing all logs
  3. Check Volume: Use getLogVolumeReport() to identify if cleanup is needed
  4. Monitor Resource Usage: Check Salesforce org limits and usage


Last updated: 2025-06-30 | Version: 1.0.0