Exception Handling

Best practices for error logging and debugging with Triton, including exception handling patterns and debugging strategies.

Best Practices for Error Logging

Effective exception handling is crucial for debugging and monitoring. Triton provides powerful capabilities for capturing comprehensive error information.

Exception Logging Patterns

Basic Exception Logging

try {
    // Business logic
    processAccount(account);
} catch (Exception e) {
    // Always log errors
    Triton.instance.addError(TritonTypes.Area.Accounts, e);
}

Advanced Exception Logging with Context

public class ExceptionHandlingService {
    public static void processWithExceptionHandling(Id recordId) {
        // Set up template for error handling
        Triton.instance.setTemplate(
            Triton.makeBuilder()
                .category(TritonTypes.Category.Apex)
                .type(TritonTypes.Type.Backend)
                .area(TritonTypes.Area.Accounts)
                .relatedObject(recordId)
        );
        
        try {
            // Business logic
            processRecord(recordId);
            
        } catch (DmlException e) {
            // Handle DML-specific errors
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('DML operation failed')
                    .details('recordId=' + recordId + ', operation=update')
            );
            throw e;
            
        } catch (CalloutException e) {
            // Handle callout-specific errors
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('External API call failed')
                    .details('recordId=' + recordId + ', endpoint=external-service')
            );
            throw e;
            
        } catch (Exception e) {
            // Handle all other errors
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('Unexpected error occurred')
                    .details('recordId=' + recordId + ', context=record-processing')
            );
            throw e;
        }
    }
}

Real-World Exception Handling Example

// Integration service with comprehensive error handling
public class IntegrationService {
    public static void callExternalAPI(String endpoint, String payload) {
        Long startTime = System.now().getTime();
        
        // Set up template for integration operations
        Triton.instance.setTemplate(
            Triton.makeBuilder()
                .category(TritonTypes.Category.Integration)
                .type(TritonTypes.Type.Backend)
                .area(TritonTypes.Area.ExternalAPI)
        );
        
        HttpRequest req = new HttpRequest();
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setBody(payload);
        
        try {
            HttpResponse response = new Http().send(req);
            
            if (response.getStatusCode() == 200) {
                // Log successful call
                Triton.instance.log(
                    Triton.instance.fromTemplate()
                        .summary('External API call successful')
                        .details('endpoint=' + endpoint + ', statusCode=' + response.getStatusCode())
                        .integrationPayload(req, response)
                        .duration(System.now().getTime() - startTime)
                );
            } else {
                // Log HTTP error
                Triton.instance.log(
                    Triton.instance.fromTemplate()
                        .exception(new IntegrationException('HTTP ' + response.getStatusCode() + ': ' + response.getBody()))
                        .summary('External API call failed')
                        .details('endpoint=' + endpoint + ', statusCode=' + response.getStatusCode())
                        .integrationPayload(req, response)
                        .duration(System.now().getTime() - startTime)
                );
            }
            
        } catch (CalloutException e) {
            // Log callout exception
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('External API callout failed')
                    .details('endpoint=' + endpoint + ', error=' + e.getMessage())
                    .integrationPayload(req, null)
                    .duration(System.now().getTime() - startTime)
            );
            throw e;
            
        } catch (Exception e) {
            // Log unexpected errors
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('External API call failed')
                    .details('endpoint=' + endpoint + ', error=' + e.getMessage())
                    .integrationPayload(req, null)
                    .duration(System.now().getTime() - startTime)
            );
            throw e;
        }
    }
}

LWC Exception Handling

// LWC component with comprehensive error handling
export default class ErrorHandlingComponent extends LightningElement {
    triton;
    
    connectedCallback() {
        this.triton = new Triton().bindToComponent('c-error-handling');
        
        // Set up template for error handling
        this.triton.setTemplate(
            this.triton.makeBuilder()
                .type(TYPE.FRONTEND)
                .area(AREA.COMMUNITY)
                .relatedObjects([this.recordId])
        );
    }
    
    async handleDataOperation() {
        try {
            const result = await performDataOperation({ 
                recordId: this.recordId,
                data: this.formData 
            });
            
            // Log success
            this.triton.log(
                this.triton.fromTemplate()
                    .summary('Data operation completed')
                    .details(JSON.stringify({ result: result.Id }))
            );
            
        } catch (error) {
            // Log error with full context
            await this.triton.logNow(
                this.triton.fromTemplate()
                    .exception(error)
                    .summary('Data operation failed')
                    .details(JSON.stringify({
                        recordId: this.recordId,
                        formData: this.formData,
                        errorMessage: error.message,
                        errorStack: error.stack
                    }))
            );
            
            // Show user-friendly error
            this.showErrorMessage('Operation failed. Please try again or contact support.');
        }
    }
    
    // Handle wire errors
    @wire(getData, { recordId: '$recordId' })
    wiredData({ error, data }) {
        if (error) {
            this.triton.logNow(
                this.triton.fromTemplate()
                    .exception(error)
                    .summary('Wire error')
                    .relatedObjects([this.recordId])
            );
        }
    }
}

Exception Types and Handling

DML Exceptions

try {
    insert records;
} catch (DmlException e) {
    Triton.instance.log(
        Triton.instance.fromTemplate()
            .exception(e)
            .summary('DML operation failed')
            .details('operation=insert, recordCount=' + records.size())
    );
    
    // Handle specific DML error codes
    for (Integer i = 0; i < e.getNumDml(); i++) {
        String errorMessage = e.getDmlMessage(i);
        Integer errorCode = e.getDmlStatusCode(i);
        
        Triton.instance.log(
            Triton.instance.fromTemplate()
                .summary('DML error detail')
                .details('recordIndex=' + i + ', errorCode=' + errorCode + ', message=' + errorMessage)
        );
    }
    throw e;
}

Callout Exceptions

try {
    HttpResponse response = new Http().send(request);
} catch (CalloutException e) {
    Triton.instance.log(
        Triton.instance.fromTemplate()
            .exception(e)
            .summary('Callout failed')
            .details('endpoint=' + request.getEndpoint() + ', method=' + request.getMethod())
            .integrationPayload(request, null)
    );
    throw e;
}

Custom Exceptions

public class BusinessLogicException extends Exception {
    public String businessContext;
    public String operation;
    
    public BusinessLogicException(String message, String context, String op) {
        this(message);
        this.businessContext = context;
        this.operation = op;
    }
}

// Usage
try {
    validateBusinessRules(account);
} catch (BusinessLogicException e) {
    Triton.instance.log(
        Triton.instance.fromTemplate()
            .exception(e)
            .summary('Business validation failed')
            .details('context=' + e.businessContext + ', operation=' + e.operation)
    );
    throw e;
}

Debugging Strategies

Stack Trace Analysis

public class StackTraceAnalyzer {
    public static void logWithStackTrace(Exception e, String context) {
        String stackTrace = e.getStackTraceString();
        
        Triton.instance.log(
            Triton.instance.fromTemplate()
                .exception(e)
                .summary('Exception with stack trace')
                .details('context=' + context + ', stackTrace=' + stackTrace)
        );
    }
}

Performance Monitoring

public class PerformanceMonitor {
    public static void monitorOperation(String operationName, Callable operation) {
        Long startTime = System.now().getTime();
        
        try {
            operation.call();
            
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .summary('Operation completed successfully')
                    .details('operation=' + operationName)
                    .duration(System.now().getTime() - startTime)
            );
            
        } catch (Exception e) {
            Triton.instance.log(
                Triton.instance.fromTemplate()
                    .exception(e)
                    .summary('Operation failed')
                    .details('operation=' + operationName)
                    .duration(System.now().getTime() - startTime)
            );
            throw e;
        }
    }
}

Best Practices

Error Logging Guidelines

  1. Always log exceptions: Never let exceptions go unlogged

  2. Include context: Add relevant business context to error logs

  3. Use appropriate levels: Use ERROR level for exceptions

  4. Flush immediately: Use log() instead of addLog() for errors

  5. Preserve stack traces: Include full exception information

  6. Add business context: Include relevant IDs, operation details, and state

Exception Handling Patterns

  1. Specific exception types: Handle different exception types appropriately

  2. Graceful degradation: Implement fallback behavior when possible

  3. User-friendly messages: Provide meaningful error messages to users

  4. Recovery strategies: Implement retry logic for transient failures

  5. Monitoring integration: Ensure errors are visible in monitoring systems

Debugging Support

  1. Rich context: Include all relevant information for debugging

  2. Performance metrics: Track timing and resource usage

  3. State preservation: Log system state at time of error

  4. Correlation IDs: Use transaction IDs to correlate related errors

  5. Progressive detail: Start with high-level errors, add detail as needed

By following these exception handling best practices, you'll create robust error logging that enables effective debugging and monitoring across your Salesforce org.

Last updated