NebulaLogger icon indicating copy to clipboard operation
NebulaLogger copied to clipboard

Send Email for Error Logs

Open jongpie opened this issue 1 year ago • 6 comments

Discussed in https://github.com/jongpie/NebulaLogger/discussions/341

Originally posted by fentes July 21, 2022 Hey Jongpie,

we are logging quite often and the logs are very helpful at debugging stuff. The issue we are facing is, that we need to look into the Logs/Dashboard in order to see that there was an error.

For many other issues like flow errors or Apex exceptions we are getting an email to a shared email inbox and then someone of the team investigates into that. So we are quite good if something really breaks, but there can also be some things which are business wise wrong but executed successful. We would see it if, we look into the logs, but pulling is not as reliable than pushing 😉.

To solve this gap, I want to send an email to the team whenever a Log was saved which contains an error. I saw that you already created a class called LoggerEmailSender to send an email if something within the framework crashed. I understood the documentation that its purpose is only for crashes. Can we maybe reuse the class for sending additional emails?

Wanted to ask about that before I write a custom trigger to send emails by myself.

jongpie avatar Aug 09 '22 02:08 jongpie

A little plugin for this purpose. It uses a Lightning Email Template to build the Subject and Body with the merge fields of the Log__c Object.

  • The LoggerParameter Email_Template_Name is a String containing the name of the template to Query.

  • The LoggerParameter Email_Address_List is a JSON formatted String List, containing the recipients for the email.

  • The sendEmailWithTemplate method can be refactored into an Utils Class and can be used for every scenario.

The problem with this approach is that the saveLog() Method MUST use the SYNCHRONOUS_DML save operation.

`

@SuppressWarnings('PMD.ExcessivePublicCount')
public without sharing class NebulaLoggerTriggerHandler implements LoggerPlugin.Triggerable {

    
    @TestVisible
    private static final String EMAIL_TEMPLATE_NAME = LoggerParameter.getString('Email_Template_Name', null);
    @TestVisible
    private static final List<String> TO_ADRESSES = LoggerParameter.getStringList('Email_Address_List',  null);

    private List<Log__c> logs;

    /**
     * @description Default constructor
     */
    @SuppressWarnings('PMD.EmptyStatementBlock')
    public NebulaLoggerTriggerHandler() {
    }

    /**
     * @description This method is automatically called by Nebula Logger's plugin framework.
     * @param  configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin
     * @param  input The instance of `LoggerTriggerableContext`, provided by the logging system
     */
    @SuppressWarnings('PMD.ExcessiveParameterList')
    public void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input) {
        
        if (input.sobjectType != Schema.Log__c.SObjectType)  return;
  
        this.logs = (List<Log__c>) input.triggerNew;

        switch on input.triggerOperationType {
            when BEFORE_INSERT {  this.handleBeforeInsert(); }
            when AFTER_INSERT  {  this.handleAfterInsert();  }
            when BEFORE_UPDATE {  this.handleBeforeUpdate(); }
            when AFTER_UPDATE  {  this.handleAfterUpdate();  }
            when BEFORE_DELETE {  this.handleBeforeDelete(); }
            when AFTER_DELETE  {  this.handleAfterDelete();  }
            
            when else {return;}
        }
    }

    public void handleBeforeInsert() { return; }
    
    public void handleAfterInsert() { return; }
    
    public void handleBeforeUpdate() { return; }
    
    public void handleAfterUpdate()  { 
        this.sendEmailError();
        return; 
    }

    public void handleBeforeDelete() { return; }
    
    public void handleAfterDelete()  { return; }

  
    private void sendEmailError() {
        for (Log__c log : this.logs) {
            if (log.TotalERRORLogEntries__c > 0 || log.TotalWARNLogEntries__c > 0) {
                this.sendEmailWithTemplate('Nebula Logger', EMAIL_TEMPLATE_NAME, TO_ADRESSES, log);  
            }
        }
    }

    @SuppressWarnings('PMD.ExcessiveParameterList')
    private static void sendEmailWithTemplate(String senderDisplayName, String templateName, List<String> toAddresses, SObject relatedRecord){
        
        //Get template id
        ID emailTemplateId = [SELECT Id FROM EmailTemplate WHERE Name =:templateName LIMIT 1].Id;
        
        Messaging.SingleEmailMessage email = Messaging.renderStoredEmailTemplate(emailTemplateId, UserInfo.getUserId(), relatedRecord.Id);
        email.setTargetObjectId(UserInfo.getUserId());
        email.setSubject(email.getSubject());
        email.setPlainTextBody(email.getPlainTextBody());
        email.setSenderDisplayName(senderDisplayName);
        email.setReplyTo('[email protected]');
        email.setUseSignature(false);
        email.setBccSender(false);
        email.setSaveAsActivity(false);
        email.toAddresses = toAddresses;

        Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage>{ email };

        Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);

        if (results[0].success) {
            System.debug('The email was sent successfully.');
        } else {
            System.debug('The email failed to send: ' + results[0].errors[0].message);
        }
    }
}`

NX-Mirco-Centrone avatar Aug 16 '22 09:08 NX-Mirco-Centrone

@NX-Mirco-Centrone very nice!! Thanks so much for putting this code together - I'm going to try to work on adding this into the core package hopefully sometime next month (along with a LoggerParameter__mdt custom metadata record so that orgs can choose to enable or disable the feature). I have a few ideas on how to avoid the need to use the SYNCHRONOUS_DML save method, I'll see what I can do with that part.

jongpie avatar Aug 18 '22 18:08 jongpie

Hey @jongpie,

I had a discussion with the team, and some concerns came up, that this can end up in spamming the inbox. So I'm not sure anymore whether it is a good approach to send out mails immediately and always.

Maybe it is more helpful to individually define that, based on rules, like with retention rules. But in case it is not urgent (probably most of the time), we can also build a standard report and schedule it. With reports the logs can also be grouped, so that there is only one mail and not 10 single ones.

I'll set up some reports, schedule them and see whether this is already enough.

fentes avatar Aug 26 '22 08:08 fentes

I had a discussion with the team, and some concerns came up, that this can end up in spamming the inbox. So I'm not sure anymore whether it is a good approach to send out mails immediately and always.

@fentes in my opinion if you have so many Logs that end up with ERROR or WARN entries. The problem is in the implementation of the Logging methods itself.

NX-Mirco-Centrone avatar Aug 26 '22 10:08 NX-Mirco-Centrone

@fentes and @NX-Mirco-Centrone thanks for sharing your insights! I think there could definitely be issues with emails spamming an address in the event that there are a lot of error logs generated in a short time span. But I think it still makes sense for Nebula Logger to offer at least a simple way to send email alerts, given how ubiquitous email is. I'm going to explore a few possible options for how this could be offered, but at the moment, I still like the idea of adding some extra fields on LoggerSettings__c to make it easy to configure at the org/profile/user-levels.

I'm planning to work on a few other items first, but I'll try to circle back to this issue in the near future, and will keep you updated on any progress or follow-up questions.

jongpie avatar Aug 28 '22 19:08 jongpie

I had a discussion with the team, and some concerns came up, that this can end up in spamming the inbox. So I'm not sure anymore whether it is a good approach to send out mails immediately and always.

@fentes in my opinion if you have so many Logs that end up with ERROR or WARN entries. The problem is in the implementation of the Logging methods itself.

@NX-Mirco-Centrone 😂 you're right, focus should be to have no error logs. I looked into our statistics and found 33 error logs in the last 60 days. But all of them were only created on 5 days. So most of the time silence, but when something happens, a many errors occur at once.

fentes avatar Aug 30 '22 14:08 fentes