Debugging Tools & Techniques
📖 Concept
Effective debugging in Salesforce requires mastering multiple tools — debug logs, Developer Console, VS Code debugging, and monitoring tools.
Debugging tools:
Debug Logs
- Configure via Setup → Debug Logs
- Set log levels per category (Database, Apex, Workflow, etc.)
- Each log has a size limit (5MB for Developer Console, 20MB total)
- Persist for 24 hours (or until overwritten)
- Critical sections: SOQL_EXECUTE, DML_BEGIN, USER_DEBUG, LIMIT_USAGE
Developer Console
- Execute anonymous Apex
- View and analyze debug logs
- Query Plan tool for SOQL optimization
- Test runner with code coverage
- Performance profiling via timeline
VS Code with Salesforce Extensions
- Replay Debugger — step through debug logs
- ISV Debugger — real-time debugging (ISV only)
- Apex Test Sidebar — run/debug tests
- SOQL Builder — visual query construction
Monitoring & Alerting
- Event Monitoring (Shield) — user activity tracking
- Apex Exception Emails — automatic error notifications
- Custom error logging — Error_Log__c custom object
- Health Check — security scanning
- Salesforce Optimizer — org health analysis
Debug log anatomy:
EXECUTION_STARTED — Transaction begins
CODE_UNIT_STARTED — Trigger/class entry
SOQL_EXECUTE_BEGIN/END — Each SOQL query with timing
DML_BEGIN/END — Each DML operation
USER_DEBUG — System.debug() output
VARIABLE_SCOPE_BEGIN/END — Variable values (FINER level)
LIMIT_USAGE_FOR_NS — Governor limit consumption
CUMULATIVE_LIMIT_USAGE — Total limits used in transaction
EXECUTION_FINISHED — Transaction complete
💻 Code Example
1// Debugging Patterns & Techniques23public class DebuggingService {45 // 1. Structured debug logging6 public static void debugLog(String className, String methodName, String message) {7 System.debug(LoggingLevel.INFO,8 '[' + className + '.' + methodName + '] ' + message);9 }1011 public static void debugLog(String className, String methodName,12 String message, Object data) {13 System.debug(LoggingLevel.INFO,14 '[' + className + '.' + methodName + '] ' + message +15 ' | Data: ' + JSON.serialize(data));16 }1718 // 2. Transaction-level debugging19 public static void debugTransaction(String context) {20 System.debug(LoggingLevel.INFO, '=== Transaction Debug: ' + context + ' ===');21 System.debug(LoggingLevel.INFO, 'User: ' + UserInfo.getUserId());22 System.debug(LoggingLevel.INFO, 'SOQL: ' + Limits.getQueries() + '/' + Limits.getLimitQueries());23 System.debug(LoggingLevel.INFO, 'DML: ' + Limits.getDmlStatements() + '/' + Limits.getLimitDmlStatements());24 System.debug(LoggingLevel.INFO, 'CPU: ' + Limits.getCpuTime() + 'ms/' + Limits.getLimitCpuTime() + 'ms');25 System.debug(LoggingLevel.INFO, 'Heap: ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());26 }2728 // 3. Conditional debugging (avoid heap in production)29 private static Boolean isDebugEnabled = false;3031 public static void enableDebug() { isDebugEnabled = true; }3233 public static void conditionalDebug(String message, Object data) {34 if (isDebugEnabled) {35 System.debug(LoggingLevel.DEBUG, message + ': ' + JSON.serialize(data));36 }37 }3839 // 4. Error tracking with custom object40 public static void logError(Exception e, String context) {41 try {42 insert new Error_Log__c(43 Class_Name__c = context,44 Error_Message__c = e.getMessage()?.left(255),45 Stack_Trace__c = e.getStackTraceString()?.left(32000),46 Error_Type__c = e.getTypeName(),47 Line_Number__c = e.getLineNumber(),48 User__c = UserInfo.getUserId(),49 Timestamp__c = Datetime.now(),50 Transaction_Id__c = Request.getCurrent().getRequestId()51 );52 } catch (Exception logError) {53 System.debug(LoggingLevel.ERROR, 'Failed to log error: ' + logError.getMessage());54 }55 }5657 // 5. Trigger debugging — trace what triggered the execution58 public static void debugTriggerContext() {59 System.debug(LoggingLevel.INFO, '=== Trigger Context ===');60 System.debug(LoggingLevel.INFO, 'isBefore: ' + Trigger.isBefore);61 System.debug(LoggingLevel.INFO, 'isAfter: ' + Trigger.isAfter);62 System.debug(LoggingLevel.INFO, 'isInsert: ' + Trigger.isInsert);63 System.debug(LoggingLevel.INFO, 'isUpdate: ' + Trigger.isUpdate);64 System.debug(LoggingLevel.INFO, 'isDelete: ' + Trigger.isDelete);65 System.debug(LoggingLevel.INFO, 'size: ' + Trigger.size);66 System.debug(LoggingLevel.INFO, 'new: ' + (Trigger.new != null ? Trigger.new.size() : 0));67 System.debug(LoggingLevel.INFO, 'old: ' + (Trigger.old != null ? Trigger.old.size() : 0));68 }6970 // 6. Anonymous Apex debugging scripts71 // Execute in Developer Console → Execute Anonymous7273 // Quick data check74 // List<Account> accs = [SELECT Id, Name, Industry FROM Account LIMIT 5];75 // System.debug(JSON.serializePretty(accs));7677 // Test a specific method78 // try {79 // OpportunityService.closeDeals(new Set<Id>{'006xxxxxxxxxxxx'});80 // System.debug('SUCCESS');81 // } catch (Exception e) {82 // System.debug('ERROR: ' + e.getMessage());83 // System.debug('STACK: ' + e.getStackTraceString());84 // }8586 // Check sharing visibility87 // List<AccountShare> shares = [88 // SELECT AccountId, UserOrGroupId, AccountAccessLevel, RowCause89 // FROM AccountShare WHERE AccountId = '001xxxxxxxxxxxx'90 // ];91 // System.debug(JSON.serializePretty(shares));92}
🏋️ Practice Exercise
Debugging Practice:
- Set up debug logs for your user and analyze a complex transaction (trigger → flow → trigger)
- Use the Developer Console Timeline to identify the slowest operation in a transaction
- Write a structured logging utility that captures class, method, and context
- Create an Error_Log__c object and build an error tracking system
- Use Anonymous Apex to reproduce and debug a specific production issue
- Set up the VS Code Replay Debugger to step through a captured debug log
- Build a debugging dashboard that shows error trends over time
- Implement conditional debugging that can be toggled per user via Custom Setting
- Write a script that audits all sharing rules affecting a specific record
- Create a production monitoring alert that fires when error rates exceed thresholds
⚠️ Common Mistakes
Leaving System.debug statements in production code — they consume CPU time and heap even if no one reads the logs. Use conditional debugging or remove before deploy
Debug log size truncation — logs over 5MB are truncated. Reduce log levels for categories you don't need (set to WARN or NONE)
Not using structured log format — random debug messages are impossible to search. Always include class name, method name, and context
Debugging production with FINEST level — this generates massive logs and can impact org performance. Use INFO/DEBUG for production
Not checking CUMULATIVE_LIMIT_USAGE — the section at the end of debug logs shows total limit consumption, including all triggers and automations
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Debugging Tools & Techniques. Login to unlock this feature.