How to Read Salesforce Apex Debug Logs (Step by Step)
To read a Salesforce Apex debug log: enable a trace flag in Setup → Debug Logs, run the action you want to trace, open the newest log, find the EXECUTION_STARTED boundary, then follow CODE_UNIT_STARTED events to see which triggers, classes and flows ran — and search for EXCEPTION_THROWN or LIMIT_USAGE_FOR_NS to find failures.
Step 1 — Enable a trace flag
Salesforce only writes debug logs while an active trace flag exists for the user being traced. In Setup, search Debug Logs → New under User Trace Flags, pick the user, a time window, and a debug level. Two gotchas:
- Trace flags expire — a "why is no log generating?" mystery is almost always an expired flag.
- The debug level decides what the log contains. Too low and your clue isn't logged; too high and the log truncates.
ForceLens's Smart Capture collapses this whole step: one click creates the trace flag, watches for new logs, and opens them analyzed. See how Smart Capture works.
Step 2 — Choose log levels deliberately
| Category | Everyday debugging | SOQL investigation | When log truncates |
|---|---|---|---|
| ApexCode | FINEST | FINE | DEBUG |
| ApexProfiling | INFO | INFO | NONE |
| Database | INFO | FINEST | INFO |
| System | DEBUG | INFO | INFO |
| Workflow | INFO | INFO | ERROR |
| Validation | INFO | INFO | ERROR |
Higher levels log more. FINEST on ApexCode includes every statement and variable assignment; on a big transaction that alone can blow the 20 MB cap.
Step 3 — Understand the anatomy of a log line
14:23:07.0 (5348351)|SOQL_EXECUTE_BEGIN|[12]|Aggregations:0|SELECT Id, Name FROM Account WHERE Id IN :accountIds
14:23:07.0— wall-clock timestamp.(5348351)— elapsed time in nanoseconds since transaction start. Subtract two of these to measure a block's duration.SOQL_EXECUTE_BEGIN— the event type.[12]— the Apex line number that emitted it.- The rest is event-specific detail — here, the query text.
Step 4 — Follow the key events
| Event | Use it to… |
|---|---|
EXECUTION_STARTED / FINISHED | Bound the transaction. Multiple pairs in one file mean multiple transactions logged together. |
CODE_UNIT_STARTED / FINISHED | Map the call skeleton: each trigger, class entry point, Flow, or workflow evaluation. |
SOQL_EXECUTE_BEGIN / END | See each query and its row count. Repeated identical queries = query in a loop. |
DML_BEGIN / END | See inserts/updates and rows affected — the entry points for trigger recursion. |
USER_DEBUG | Find your own System.debug() output fast (search for the literal string). |
EXCEPTION_THROWN / FATAL_ERROR | Get the exception type, message, and stack trace. FATAL_ERROR is what actually rolled back the transaction. |
LIMIT_USAGE_FOR_NS | Read final governor limit consumption per namespace — what the numbers mean. |
Step 5 — Common gotchas
- "MAXIMUM DEBUG LOG SIZE REACHED". The log hit 20 MB and lines were skipped. Lower noisy categories or scope tracing to one class.
- The error isn't in this log. Async work (future methods, queueables, batch chunks) runs in separate transactions with separate logs.
- Managed package code is hidden. Other namespaces log at their own levels and much of their internals won't appear.
- Recursion reads as duplication. If a trigger updates its own object, you'll see the same trigger's CODE_UNIT twice. That's re-entry, not a duplicate log.
Doing all of this in one click
Everything above is what a debug log analyzer automates. ForceLens parses the log in your browser and gives you the execution tree, order of execution, SOQL/DML aggregation, error surfacing and limits report as clickable tabs — free, with nothing uploaded anywhere.
Frequently asked questions
How do I enable debug logs in Salesforce?
In Setup, search for Debug Logs, click New under User Trace Flags, pick the user, a start/expiry time, and a debug level (SFDC_DevConsole is a common default). Logs then generate for every transaction that user runs until the flag expires.
Why is my debug log truncated?
Debug logs are capped at 20 MB per transaction. When a log exceeds the cap, Salesforce skips lines (you'll see "*** Skipped" markers). Reduce log levels for noisy categories like System and Validation, or scope tracing to a specific class.
What log level should I use for Apex debugging?
Start with ApexCode=FINEST, ApexProfiling=INFO, Database=INFO, System=DEBUG. Raise Database to FINEST for SOQL investigations; lower ApexCode if the log truncates.
Where are debug logs stored and for how long?
Setup → Debug Logs. System-generated logs are retained for 24 hours and the org caps total log storage at 1,000 MB — older logs are deleted as new ones arrive, so save anything important promptly (ForceLens keeps your last 200 analyzed sessions locally).
Skip the manual steps
ForceLens sets the trace flag, captures the log, and opens it analyzed — in one click, free, entirely in your browser.