Logging of Exceptions in Salesforce

Logging of Exceptions in Salesforce

January 11, 2018

Unpredicted behaviour in a custom code. Can we eliminate it?

The ability to customize your Salesforce org code is not just a “nice to have.”  It greatly increases the capability and flexibility of Salesforce.

However, custom code can also be tricky to use. It would be great if we could detect unpredicted behavior in our custom code through functionality, such as catching and logging exceptions.

Lightning Components

There is no problem to logging exceptions in Lightning Components. JavaScript code can be surrounded in a try catch block. As a result we can easily track any type of client side exceptions:

doSomething: function(component) {

   try {

       unexistingMethod(); // ReferenceError here

   } catch(e) {

       // log exception here

   }

}

It is up to you what to do with such errors. It can be JavaScript console output:

console.error(e);

or Lightning notification to user:

var toastEvent = $A.get(“e.force:showToast”);

toastEvent.setParams({

   “title”: e.name,

   “message”: e.message,

   “mode”: “sticky”,

   “type”: “Error”

});

toastEvent.fire();

In the case where some exceptions happen at a server Apex controller, we are also on a safe side through the use of a special type of exception – AuraHandledException.  We can convert any exception into an AuraHandledException and send it to Lightning Component as a response:

@AuraEnabled
public static String serverMethod(String name) {
   try {

       // some Apex code

   } catch(DMLException ex) {

       throw new AuraHandledException(‘Unable to save record’);

   }
}

Please, note, AuraHandledException supports String argument only. This class is not extensible. If you need to send some data to client side use the following approach:

  • create Apex class to hold the data.
  • serialize it as JSON.
  • pass it to the AuraHandledException.
  • deserialize it on the client side and work with data as an object.

Apex

The situation with a pure Apex code is slightly more complicated. We can set up an Apex Exception Email that will send an unhandled exception to an Administrator’s mailbox. However, in many cases this is not enough. Here are some of the disadvantages,

  • Email context is not configurable. It contains an Apex stack trace, Org ID and User ID.
  • Exceptions from all managed packages will be sent. There is no way to subscribe to a specific application.
  • We are unable to make automatic responses in case of such exceptions.

Let’s overview the tools we can use in Salesforce to resolve it.

Rollback of execution context

Salesforce has a unique feature to commit any transaction to a database automatically. The System will persist changes after the execution context is finished if no unhandled exception occurs.

This approach is handy, and in most cases it is exactly what you want.  But if an unhandled exception occurs, it rolls back everything, not only DML operations. Scheduled jobs, future methods, batches, queueable jobs, emails will not be run or sent.  That is why the following piece of code will never work:

public void someMethod() {
   try {

       // some Apex code

   } catch(Exception ex) {

       // log exception here

       throw ex; // rethrow exception again

   }
}

By rethrowing an exception, you add an unhandled exception into the execution context.

macbook_screen_CoreValue_salesforceDo we need to catch all exceptions?

The simple answer is no. For example, you are doing a complex validation in an Apex trigger. Any call of addError() method is a DMLException. We are not interested in catching such exceptions.

The best practice is to catch exceptions in a top level component, e.g., Web service, controller of Visualforce page, server side controller of Lightning Component, etc. In other words, in any place where an execution context will start.

Adding a try .. catch block to all of your methods can ruin the readability of your code. It also increases the complexity of writing unit tests.

What is more important, by catching exceptions you are braking the logic of your application. You are forcing low level components to be responsible for decisions, e.g., what to do in a critical situation.

From time to time you can also get an exception you would never expect. For example, while your code is sending email to Contact, the following is received:

System.EmailException: INVALID_EMAIL_ADDRESS, email address has bounced

Such things are really hard to predict, and the reason we must be able to log exceptions.

Logging exceptions

Let’s imagine we want to log an exception in a custom Apex code. For this purpose we can use a custom object to store such exceptions. Let’s say ErrorLog__c object. Look at the code below:

public static void someMethod(String name) {
   try {

       // Apex code here

   } catch(Exception ex) {

       ErrorLog__c log = new ErrorLog__c(

           Description__c = ‘Error: ‘ + ex.getMessage()

       );

       insert log;

   }
}

This code will work if the execution context is clean, i.e., when there is no unhandled exception. However, if this code is a part in a chain of the execution context, it might not work. Look at the diagram below:

salesforce_exception_draw_CoreValue

If an exception occurs after inserting the error log record into a database, the entire transaction will be rolled back. Your ErrorLog__c record will not be saved.

Logging system with Platform Events

The situation has totally changed with Platform Events. It is a new feature generally available since the Summer ’17 release (API version 40.0). Platform Event is a bus to send read only messages. When the message is sent, you are not able to return it.  We will use this feature in the error logging system.
The idea is simple. When you need to save a new ErrorLog__c record, publish a Platform Event.  Later, you can subscribe to this event and save the ErrorLog__c record in the database:

drawing Salesforce_CoreValue

What’s more important, we are not limited in logging the exception. We can react to it. It can be an email message to a system administrator or running the Apex method to repeat the failed operation, as well as many more uses.

Final thoughts

Platform Events is a great tool for an event-driven software architecture. They extend programming functionalities in Apex, and can be used even in an execution context with an unhandled exception.

Senior Engineer, CoreValue

Tags

CoreValueLightning experienceSalesforceSalesforce Lightning

Share


Recent Articles

Get 100% Code Coverage for Salesforce Custom Metadata Based Decisions

January 18, 2018 | Bohdan Dovhan

How to obtain a full coverage for code which uses Custom Metadata for strategy-like decision implementation? Introduction Many applications use configuration data. Configuration data might be relevant to the entire organization, or a subset of user, or even different for each user. For the purposes of this article, we will focus only on global configuration […]

Building Mobile App for Healthcare?

January 4, 2018 | Lily Smirnova

How to develop a successful mHealth application As a response to the global digitalization of almost every aspect of our lives, there has been an explosion of healthcare mobile apps in the past few years.  According to IQVIA institute for Human Data Science, medical or health-related mobile applications account for over 318,000 apps worldwide, and […]

© Copyright - CoreValue 2018
Salesforce, Sales Cloud, and others are trademarks of salesforce.com, inc., and are used here with permission.
Used with permission from Microsoft.