There's a cruel irony in Salesforce logging: the moment you most need a log — an unhandled exception that blows up a transaction — is the exact moment your log record gets rolled back along with everything else. Platform Events solve this, and they turn logging from an afterthought into something you can actually monitor and report on.
Why normal logging fails at the worst time
The naive approach is to create a custom object, say App_Log__c, and insert a record whenever something goes wrong:
try {
doRiskyWork();
} catch (Exception e) {
insert new App_Log__c(Message__c = e.getMessage());
throw e; // re-throw so the caller knows it failed
}
Here's the trap: that insert and the re-thrown exception live in the same transaction. When the exception propagates and the transaction rolls back, Salesforce undoes all DML — including your log insert. You're left with a failure in production and no record of it. Even Database.insert with partial success doesn't help, because the rollback happens after your catch block returns.
Platform Events publish outside the transaction
A Platform Event published with the Publish Immediately behavior is committed independently of your Apex transaction. It doesn't participate in the rollback. So the pattern becomes:
- On error, publish a
Log_Event__ePlatform Event with the message, level, stack trace, and context. - Let the original transaction fail and roll back as it should.
- A trigger on the Platform Event fires in its own transaction and inserts a durable
Log__crecord.
The log now survives, because it was never part of the doomed transaction in the first place.
public static void error(String category, String message, Exception e) {
EventBus.publish(new Log_Event__e(
Level__c = 'ERROR',
Category__c = category,
Message__c = message,
Stack_Trace__c = e != null ? e.getStackTraceString() : null,
Transaction_Id__c = Request.getCurrent().getRequestId()
));
}
trigger LogEventTrigger on Log_Event__e (after insert) {
List<Log__c> logs = new List<Log__c>();
for (Log_Event__e e : Trigger.new) {
logs.add(new Log__c(
Level__c = e.Level__c,
Category__c = e.Category__c,
Message__c = e.Message__c,
Stack_Trace__c = e.Stack_Trace__c
));
}
insert logs;
}
Add level control so you're not drowning in noise
Logging everything all the time is expensive and useless. Drive a minimum level from Custom Metadata — ERROR, WARN, INFO, DEBUG, FINE — so the same code logs verbosely in a sandbox and only errors in production, with no redeploy:
if (MF_Logger.isEnabled('DEBUG')) {
MF_Logger.debug('Integration', 'Payload: ' + JSON.serialize(payload));
}
Bonus: because logs are real records, you can build reports and dashboards on error volume by category, alert on spikes, and give admins a filterable UI instead of asking a developer to open debug logs.
A viewer beats trace flags
Native debug logs are ephemeral, capped, and require trace flags on specific users. A persistent log object plus a Lightning Web Component viewer lets support and admins filter by level, category, and date range right inside the app — no Setup access, no waiting for a trace flag window. That's the model behind the MF Logger accelerator: a Platform Event, a log object, a configurable logger class, a trigger, and an mfLogViewer LWC.
When to use it
Reach for Platform Event logging any time you need to keep the record of a failure that rolls back — integration callouts, complex trigger logic, batch jobs, and anything customer-facing where "it failed silently" isn't acceptable. For pure debugging in a sandbox, native debug logs are still fine; for production observability, persistent logs win.
Frequently asked questions
Why do my log records disappear when there's an error?
If you insert logs with normal DML and the transaction later throws an unhandled exception, the whole transaction — including your logs — rolls back, so you lose the record exactly when you needed it.
How do Platform Events make logging rollback-safe?
Events published with publish-immediately are committed independently of the current transaction. A separate trigger writes them to a log object, so the log survives even if the original transaction rolls back.
Is Platform Event logging better than debug logs?
They're complementary. Debug logs are ephemeral and need trace flags; Platform Event logging persists structured, queryable records you can report on and view in an LWC — far better for production monitoring.