LET'S LEARN TOGETHER. THE BEAUTIFUL THING ABOUT LEARNING IS NOBODY CAN TAKE IT AWAY FROM YOU.

Custom Logging Framework in Salesforce

In my current project, I have a requirement where I have to implement a custom logging framework. Salesforce put the debug/exception log with System.debug() statement, but going through that debug log to identify the issue is always a challenge. So the better approach is to store the exception as soon as it occurred somewhere so that later point we can always refer that to identify what happened.

In order to achieve that below is what I did-

First I have created an object(API Name: Custom_Log__c) to store the exception logs-
Below are the custom field inside the object-

  • Class__c(Text Area(255))   From which class the exception is coming
  • Method__c(Text Area(255))  From which method the exception is coming
  • Message__c(Long Text Area(32768))  Stack trace of the exception
  • Priority__c(Picklist) - Possible values are DEBUG, ERROR, FATAL, INFO, WARNING
Now I need to create the below custom settings -
EnableCustomLogging with possible values true/false. 
The reason behind is that with EnableCustomLogging = true, exceptions will be stored in the custom object i.e. Custom_Log__c and with EnableCustomLogging = false, exception will be stored in the debug log with System.debug() 

Now with this setup, I have created the visual page.
Source Code:
<apex:page controller="CustomLogController">
    <apex:form >
        <apex:commandButton value="Divide By Zero Exception!" action="{!divideByZeroException}" />
        <br/>
        <apex:commandButton value="Null Pointer Exception!" action="{!nullPointerException}" />
    </apex:form>
</apex:page>
Now the controller - CustomLogController:
public class CustomLogController {
    public void divideByZeroException(){
        Integer number1, number2;
        try{
            number1 = 10;
            number2 = 0;
            Integer number3 = number1/number2;    
        }catch(Exception ex){
            String message = 'Error: ' + ex.getMessage() + '; Stack Trace:' + ex.getStackTraceString();
            CustomLogging.logMessage('CustomLogController', 'divideByZeroException', message, CustomLogging.WARNING);
        }
    }
    
    public void nullPointerException(){
        Contact aContact = null;
        try{
            String email = aContact.Email;
        }catch(Exception ex){
            String message = 'Error: ' + ex.getMessage() + '; Stack Trace:' + ex.getStackTraceString();
            CustomLogging.logMessage('CustomLogController', 'nullPointerException', message, CustomLogging.ERROR);
        }
    }
}
Now the CustomLogging class-
public class CustomLogging {
    
    public static String INFO = 'INFO';
    public static String DEBUG = 'DEBUG';
    public static String WARNING = 'WARNING';
    public static String ERROR = 'ERROR';
    public static String FATAL = 'FATAL';
    
    private static Boolean isEnabled(){
        Decision_Object__c enableCustomLogging = Decision_Object__c.getInstance('EnableCustomLogging');
        System.debug('IsEnabled: ' + enableCustomLogging.Value__c);
        return enableCustomLogging.Value__c;
    }
    
    public static void logMessage(String className, String methodName, String message, String Priority){
        if(isEnabled()){
            Custom_Log__c newLogMessage = new Custom_Log__c(
                Class__c = className,
                Method__c = methodName,
                Message__c = message,
                Priority__c = Priority);
            try{
                Database.insert(newLogMessage);
            }catch(Exception ex){
                System.debug(
                    'Failed to INSERT the [Apex Debug Log] ADL record. ' +
                    'Error: ' + ex.getMessage()
                );
            }
        }else{
            String completeErrorMessage = 'Error occured at class: ' + className + ' method: ' + methodName + 
                ' and the error is: ' + message;
            System.debug(completeErrorMessage);
        }
        
    }
}
And finally the test class - This is very important
@isTest
private class UnitTestCustomLogController {
    
    private static void setEnableCustomLoggingFlag(Boolean value){
        insert(new Decision_Object__c(Name='EnableCustomLogging', Value__c=value));
    }
    
    static testMethod void testWhetherCustomLoggingIsGettingCreatedWhileDisabled() {
        setEnableCustomLoggingFlag(false);
        CustomLogController customLogController = new CustomLogController();
        customLogController.divideByZeroException();
        
        Integer numberOfCustomLogs= [Select count() From Custom_Log__c];
        System.assertEquals(0, numberOfCustomLogs);
    }
    
    static testMethod void testDivideByZeroException(){
        setEnableCustomLoggingFlag(true);
        CustomLogController customLogController = new CustomLogController();
        customLogController.divideByZeroException();
        
        Integer numberOfCustomLogs= [Select count() From Custom_Log__c];
        Custom_Log__c customLog= [Select Class__c, Priority__c, Method__c, Message__c From Custom_Log__c LIMIT 1];
        System.assertEquals('CustomLogController', customLog.Class__c);
        System.assertEquals('divideByZeroException', customLog.Method__c);
        System.assertEquals(CustomLogging.WARNING, customLog.Priority__c);
    }
    
    static testMethod void testNullPointerException(){
        setEnableCustomLoggingFlag(true);
        CustomLogController customLogController = new CustomLogController();
        customLogController.nullPointerException();
        
        Integer numberOfCustomLogs= [Select count() From Custom_Log__c];
        Custom_Log__c customLog= [Select Class__c, Priority__c, Method__c, Message__c From Custom_Log__c LIMIT 1];
        System.assertEquals('CustomLogController', customLog.Class__c);
        System.assertEquals('nullPointerException', customLog.Method__c);
        System.assertEquals(CustomLogging.ERROR, customLog.Priority__c);
    }
}
Done. That's all.
So now if I click on any of the buttons in VisualForce page and EnableCustomLogging = true, I can see one record is getting inserted into the Custom_Log__c object like below-
If you have any feedback, please share. Thanks.

Share:

No comments:

Post a Comment

Never miss a post. Subscribe to get latest blog posts, right into your email box.

* indicates required

Labels

Salesforce (105) Apex (52) admin (28) visualforce (21) ADM (20) dev 501 (19) lightning (19) integration (18) learn salesforce (18) 501 (16) javascript (14) SOAP (13) tutorial (11) Advanced Apex (10) Certification. (10) Kitchener Developer Group (8) Trigger (8) test class (8) Certification (7) flow (7) security (7) unit testing (7) Advanced Admin (6) Lightning Experience (6) SOQL (6) Sharing and Visibility (6) design pattern (6) developer (6) report (6) salesforce release (6) service cloud (6) trailhead (6) use case (6) Lightning Feature (5) New Features (5) css (5) dashboard (5) debug (5) formula (5) mobile (5) solution management (5) JSON (4) Kitchener User Group (4) Knowledge Management (4) Lightning Web Component (4) New Feature (4) Sales Cloud (4) Salesforce DX (4) Tips (4) WebSphere (4) best practice (4) cast iron (4) component (4) deployment (4) event (4) github (4) html (4) map (4) polymer (4) profiles (4) release (4) responsive (4) tdd (4) ui (4) visual studio code (4) Architect (3) Article (3) Live Chat (3) Online Event (3) Opportunity (3) Performance (3) Products (3) REST (3) Role (3) SOSL (3) Salesforce Certification (3) Scratch Org (3) Spring 20 (3) Study Notes. (3) Summer15 (3) VS Code (3) Web Technology (3) Winter21 (3) automation tool (3) configuration (3) dynamic apex (3) license (3) mapbox (3) singleton (3) version controlling (3) AppExchange (2) Asynchronous Apex (2) Asynchronous callout (2) Aura Framework (2) Bulkify (2) Community (2) Data Architecture and Management Certification (2) Devops (2) Distributed Version Controlling (2) ES6 (2) Eclipse (2) Einstein (2) Enhancement (2) Enterprise Territory Management (2) Financial Services Cloud (2) Force.com IDE (2) Governor Limit (2) Groups (2) IBM (2) Implicit Sharing (2) JourneyToCTA (2) LWC (2) Lightning Design System (2) Live Agent (2) Metadata (2) PD II (2) Price Book (2) Queueable (2) SFDX (2) Sharing (2) Spring 15 (2) Summer17 (2) Territory (2) Virtual Event (2) ant (2) basic (2) chatter (2) code coverage (2) coding (2) communication (2) console (2) controller (2) documentation (2) dreamforce (2) git (2) jquery (2) logging (2) object (2) permission (2) process builder (2) salesforce1 (2) strategy (2) visual workflow (2) xml (2) Action Plan (1) Action Plan Template (1) Activity Timeline (1) Advanced Currency (1) Agent Productivity (1) Analytics (1) Apex Sharing (1) Arrow (1) Batch (1) Bots (1) Browser (1) Bulk data load (1) CTA (1) Calendar (1) Canon (1) Case Management (1) Celebration (1) Cheat Sheet (1) Classic (1) Compare (1) Confetti (1) Constructor (1) Contact Center (1) Continuation (1) Continuous Integration (1) Convert (1) Cookie (1) CumulusCI (1) Custom Metadata (1) Custom Object (1) Custom Permission (1) Customer (1) Data Model (1) DataCategories (1) DataGrid (1) DataTable (1) Dated Exchange Rate (1) Decorator Design Pattern (1) Dev Hub (1) Development (1) Diwali (1) EDA (1) ESLint (1) Education Cloud (1) Email (1) FSC (1) Function (1) Future (1) Global Gathering (1) Goals (1) Guest Access (1) Guest Profile (1) Guest User Sharing Rule (1) Guide (1) HEDA (1) Higher Education (1) Household (1) Husky (1) IDE (1) Ideas (1) Improvement (1) Invocable (1) KPIs (1) Knowledge (1) Large Data Volume (1) LastModifiedDate (1) Lightning Knowledge (1) Manage Currencies (1) Manual Sharing (1) Metrics (1) Multi Currency (1) New (1) OOPS (1) OWD (1) Omni-Channel (1) Optimize (1) Partner (1) Permission Set (1) Person Account (1) Photo (1) Pipeline (1) Platform Developer I (1) Platform Developer II (1) Presentation (1) Prettier (1) Product Schedule (1) Profile (1) Promise (1) Prototype (1) Public Site (1) Query Plan (1) QuickReference (1) Related records (1) Reports (1) Retrieve (1) Role Hierarchy (1) SAL (1) Salesfor (1) Salesforce Advisor Link (1) Salesforce Labs (1) Salesforce Optimizer (1) SalesforceDx (1) Schedule (1) Session (1) Sharing Rule (1) Sharing Sets (1) Site (1) Skills (1) Snap-ins (1) Spring 17 (1) Summer14 (1) Summer16 (1) Summer19 (1) Switch (1) SystemModStamp (1) Tile (1) Timeline (1) Unauthorized Access (1) User License (1) Users (1) Validation Rule (1) Web (1) Webservice (1) Winter'15 (1) Winter'17 (1) access (1) actionFunction (1) actionPoller (1) actionRegion (1) actionSupport (1) agile (1) app (1) approval process (1) aura (1) awesome (1) backup (1) bitbucket (1) book (1) campaign (1) change set (1) cli (1) code (1) csv (1) custom button (1) custom settings (1) customization (1) data loader (1) database (1) delegate Admin (1) describe (1) dom (1) duplicate (1) dynamic (1) dynamic form (1) email template (1) email-to-case (1) equals (1) error (1) field-level security (1) folder (1) ftp (1) generic (1) gift (1) global describe (1) hashcode (1) import wizard (1) jenkins (1) keynote (1) long running requests (1) monitoring (1) mysql (1) page layout (1) personal (1) power of one (1) record type (1) relationship (1) request (1) review (1) solution (1) sub-tab (1) survey (1) tab (1) username (1) workflow (1)

Popular Posts

Total Pageviews

Contact Me

Name

Email *

Message *