I currently have a trigger which sometimes fails when new information is inserted from a 3rd party system. I can't simply check the logs as it usually happens during the night and it's not easy to spot the reason (pretty complicated code). Therefore I tried to add some enhanced debugging which stores valuable information into a custom object and then inserts this into the database.
This unfortunately only works if I catch the exception. As I would prefer the system to still throw an exception if such a weird situation happens I search for a way to store my debug for later research.
I already tried with @future but even these methods do not get called if I have an exception in the trigger.
Any ideas how I can log data from a trigger for later inspection although the trigger throws an exception?
Attribution to: iwerstler
Possible Suggestion/Solution #1
Summer '17 now has Platform Events.
One of the interesting details about Platform Events from the docs:
Platform Events and Transactions
Unlike custom objects, platform events aren’t processed within database transactions in the Force.com platform. As a result, publishing platform events can’t be rolled back. Note the following:
- The
allOrNoneHeader
API header is ignored when publishing platform events through the API.- The Apex
setSavepoint()
androllback()
Database methods aren’t supported with platform events.
Note the "can't be rolled back" part. Even if your top level transaction rolls back due to an exception you can still publish an event.
The pattern would look something like:
trigger ProblemTrigger on Account (before insert) {
try {
// ... trigger.new ... throws Exception
} catch (Exception ex) {
List<DebugDetails__e> errorMessages = new List<DebugDetails__e>();
errorMessages.add(new DebugDetails__e(message__c = ex.getMessage()));
List<Database.SaveResult> results = EventBus.publish(errorMessages);
// Might need to handle railed publishing results
throw ex; // Rethrow syntax?
}
}
trigger CaptureDebugTrigger on DebugDetails__e (after insert) {
// Iterate through each notification.
for (DebugDetails__e event : Trigger.New) {
System.debug('Debug: ' + event.message__c);
// Queue insert of the persistent object with the message details.
}
// Insert the collection of error objects.
}
So you could publish and event with the required information and have a corresponding Apex trigger subscribed to the event to store the persistent message.
Attribution to: Daniel Ballinger
Possible Suggestion/Solution #2
And so you've found the reason why external "cloud" logging sites exist. Loggly.com and others like it live to serve us. Some exceptions can't be caught and all changes are rolled back in SFDC. The only log possibilities are email and cloud logging like loggly.com. Loggly.com is free for low volume accounts.
Attribution to: DaveS
Possible Suggestion/Solution #3
There is a very good wiki page on Developerforce.com on Exception handling. There you can see how to use email notifications on errors or even write an error record to a custom object.
http://wiki.developerforce.com/page/An_Introduction_to_Exception_Handling
Attribution to: Sven Delporte
Possible Suggestion/Solution #4
I would've thought handling the exception should let you insert into a log object in the finally block
Boolean exceptionOccured= false;
try{
//do something
}
catch(Exception ex){
exceptionOccured=true;
throw ex;
}
finally{
If(exceptionOccured)
//log exception XML} }
Attribution to: techtrekker
Possible Suggestion/Solution #5
If an exception is thrown in your code and you do not attempt to catch it, then SF will roll back the transaction and throw away any data inserted up until the exception is thrown.
On the surface, the behaviour you want is the somewhat unintentional side effect of not handling the transaction failure in the best manner.
I agree with the earlier comment, which is that if the exception is infrequent then catching the exception and sending an email with debug info would be the best thing to do.
Attribution to: Steven Herod
Possible Suggestion/Solution #6
As you've noticed if an apex script throws an unhandled exception everything it did is rolled back: @future, emails, DML, etc.
The good news is that there is a way to prevent a DML operation from succeeding without causing the whole apex transaction to be rolled back (except in the specific case mentioned below): the sObject.addError
method. If you call this method on every sObject in your trigger it will prevent them all from being committed to the database, however any other DML operations you perform (that of course, do not cause errors in their own triggers) will be committed successfully.
If you're looking to log to a custom object this is your best bet; catch the exception, mark everything in Trigger.new with addError, then commit your log sObject.
EXCEPTION - To summarize the edits from subsequent contact with salesforce: this will not work if every record in the trigger has errors. In this case all work done in the trigger, including @future method calls, sending email, queueing batch jobs, or performing any DML, is rolled back.
I opened a Salesforce case with partner premier support (who actually troubleshoot apex issues!) #08522717. Salesforce claims this is working as designed, and pointed me to the wiki. Which seems to suggest that setting the all or nothing flag will impact this behavior but in my testing it didn't matter - if no DML rows commit without errors all operations are rolled back.
Attribution to: ca_peterson
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1496