Diagnosing unexpected errors, null pointer exceptions, and governor limit spikes in Apex requires structured troubleshooting tools. Salesforce equips developers with both interactive debugging (stepping through code in real time) and historical log analysis (tracing execution events after runtime). Understanding how to configure these tools speeds up development and improves software quality.
1. Understanding Interactive Debugging vs. Debug Logs
Salesforce provides two primary approaches to investigate Apex execution:
- Apex Debugger (Interactive): Allows you to pause live execution in sandbox or scratch org environments, step through lines of code, inspect in-memory call stacks, and evaluate variable values dynamically.
- Apex Replay Debugger & Debug Logs: A free, log-based alternative that records transaction logs on the Salesforce platform and allows you to "replay" the execution step-by-step locally within modern IDEs like VS Code.
2. Setting Breakpoints & Stepping Through Execution
Breakpoints instruct the execution engine to pause before running a specific line of code. Once paused, you can inspect the current state and step through execution using standard debugging commands:
- Step Into (F5): Advances to the next line of code, entering inside method calls or helper classes to inspect nested logic.
- Step Over (F6): Executes the current line of code and moves to the next line in the same method without stepping into internal method implementations.
- Step Out (F7): Completes execution of the active method and returns control to the calling method.
- Continue / Resume (F8): Resumes uninterrupted code execution until the program reaches the next active breakpoint or finishes the transaction.
Placing a breakpoint inside business logic to verify collection state before performing DML:
public with sharing class OpportunityService {
public static void applyDiscount(List<Opportunity> oppList) {
for (Opportunity opp : oppList) {
// SET BREAKPOINT ON LINE BELOW:
Decimal discountFactor = calculateFactor(opp.Amount);
if (discountFactor > 0) {
opp.Amount = opp.Amount - (opp.Amount * discountFactor);
}
}
update oppList;
}
private static Decimal calculateFactor(Decimal amount) {
if (amount == null || amount <= 0) {
return 0;
}
return amount > 100000 ? 0.15 : 0.05;
}
}
- Developer Console: Built-in browser tool best suited for quick Anonymous Apex execution and viewing raw text logs.
- VS Code + Salesforce Extension Pack: Industry standard for Apex Replay Debugger, setting conditional breakpoints, and local source tracking.
- Debug Log Retention: Salesforce retains debug logs for up to 24 hours, storing up to 1,000 MB per org.
- Log File Cap: Individual debug logs are capped at 20 MB. Logs exceeding this size are truncated.
3. Capturing and Analyzing Apex Debug Logs
When interactive debugging is not feasible—such as troubleshooting production issues or analyzing asynchronous batch jobs—debug logs provide the complete execution trail.
- Configure Trace Flags: Navigate to
Setup > Debug Logsand create a Trace Flag for your automated process, specific user, or Apex class. - Select Granular Log Levels: Adjust categories such as
Apex Code,Database,Callouts, andValidationfromNONEtoFINESTdepending on the depth of diagnostics required. - Analyze Execution Flow: Search for critical events like
USER_DEBUG,SOQL_EXECUTE_BEGIN,DML_BEGIN, andLIMIT_USAGEto spot performance bottlenecks.
4. Common Traps & Debugging Best Practices
Setting log filters to
FINEST on large batch processes or trigger loops can quickly trigger Log Truncation (the 20 MB per-file limit). When a log is truncated, critical failure points and stack traces at the end of the transaction are lost. Set logging levels to INFO or DEBUG for general monitoring.
System.debug() strings in production code. Use the Apex Replay Debugger with VS Code to inspect the complete variable state without polluting code with temporary log statements.
- Always Debug in Sandboxes: Never run invasive debugging sessions, test transactions, or data rollbacks directly in a production organization.
- Use Structured Debug Levels: Structure custom logging with specific log levels (e.g.,
System.debug(LoggingLevel.ERROR, ...)) so you can filter out noise during log reviews. - Clean Up Trace Flags: Remove active trace flags after resolving issues to preserve org log storage and avoid hitting daily log generation caps.
Summary
Effective debugging is essential for maintaining resilient Salesforce applications. By combining the interactive inspection of the Apex Debugger and Replay Debugger with targeted trace flags and structured debug logs, developers can isolate bugs quickly, optimize performance, and keep custom business logic running smoothly.