Store daily running batch job logs as attachment and send email to required people

In this post we will learn how to store daily running batch job logs as attachment and send email to required group.

One question should aroused in your mind while reading this post

Why we come across this requirement ? Ans : Salesforce doesn’t store batch job log for long time, there are some certain govt limitation. Audit point of view they need batch job logs for 1 year/ 6 month / 3 month, so in this case its difficult for you to provide batch job log details to Audit team. So there could be way to raise request to Salesforce helpmate team and asked them for particular time duration batch job logs. But As per my suggestion we can customize this by our apex code and store daily running batch job logs csv file into attachment object. Also will send this CSV file as attachment into email to certain authorized people. We will send email by using Org Wide Email address.

There are some pre-requisite to achieve this functionality. 

Step 1. Create custom label in which we will store SOQL, so that we can dynamically change SOQL as per requirement.

Name : Batch_Job_Log_Query

Value: Select Id, ApexClass.Name, JobType, Status, ExtendedStatus, CreatedDate, CompletedDate, CreatedBy.Name, LastProcessed from AsyncApexJob where jobType =’BatchApex’ and Status != ‘Queued’ and CompletedDate >= YESTERDAY and CompletedDate <= YESTERDAY

Step 2. Create custom Object “BatchJobLog”

 

 

Step 3: Set Org Wide Email Address. By Using this email address we will send email to other people

Step 4: Create custom label and add email address to whom we are going to send attachment email

Step 5: Create Apex Class “AsyncApexJobDetails”


public class AsyncApexJobDetails {
public string JobId{get;set;}
public string ApexClassName{get;set;}
public string JobType{get;set;}
public string Status{get;set;}
public string NumberOfErrors{get;set;}
public string TotalJobItems{get;set;}
public string CreatedDate{get;set;}
public string CompletedDate{get;set;}
public string CreatedBy{get;set;}
}


Step 6. Create Apex Batch Job “BatchJobLogs”

global class BatchJobLogs implements Database.Batchable<sObject>, Database.stateful, Database.AllowsCallouts {

String header ='Name, Start Date, End Date, Status, Created By \n';
string finalstr='';
string recordString='';
string finalrecordString='';
string AttachmentName ='Batch Job logs - '+ System.today().Year();
Attachment atch = new Attachment();
global Database.QueryLocator Start(Database.BatchableContext bc)
{
return Database.getQueryLocator(System.Label.Batch_Job_Log_Query);
}
global void Execute(Database.BatchableContext bc, List<AsyncApexJob> scope)
{
List<AsyncApexJobDetails> lstAsyncApexJobDetails = new List<AsyncApexJobDetails>();
if(scope.size()>0)
{
for(AsyncApexJob ObjAsync : scope)
{
AsyncApexJobDetails objJobDetails = new AsyncApexJobDetails();
objJobDetails.ApexClassName = ObjAsync.ApexClass.Name;
objJobDetails.Status = ObjAsync.Status;
objJobDetails.CreatedDate =String.valueOf(ObjAsync.CreatedDate);
objJobDetails.CompletedDate =String.valueOf(ObjAsync.CompletedDate);
objJobDetails.CreatedBy =String.valueOf(ObjAsync.CreatedBy.Name);
lstAsyncApexJobDetails.add(objJobDetails);

// 'Job Name, CreatedDate, CompletedDate,JobType,Status,CreatedBy \n';
recordString = objJobDetails.ApexClassName +','+objJobDetails.CreatedDate+','+objJobDetails.CompletedDate+','+objJobDetails.Status+','+objJobDetails.CreatedBy +'\n';
finalRecordString = finalRecordString+recordString;
}
if(lstAsyncApexJobDetails.size()>0)
{
List<BatchJobLog__c> lstBatchJob=[Select Id from BatchJobLog__c where Name ='Running Batch Jobs Logs Attchment'];
if(lstBatchjob.size() == 0)
{
BatchJobLog__c obj=new BatchJobLog__c();
obj.Name='Running Batch Jobs Logs Attchment';
lstBatchJob.add(obj);
insert lstBatchJob;
}
List<Attachment> ConsoliatedAttachment =[Select Id,Name, Body from Attachment where Name =: AttachmentName Order by LastModifiedDate desc limit 1 ];

if(ConsoliatedAttachment.size()>0)
{
if(ConsoliatedAttachment[0].Name.Contains(String.valueOf(System.today().Year())))
{
finalstr = ConsoliatedAttachment[0].Body.ToString() + finalRecordString;
ConsoliatedAttachment[0].Body = Blob.valueOf(finalstr);
upsert ConsoliatedAttachment[0];
}
else
{
finalstr = header + finalrecordString;
atch.contentType = 'text/plain';
atch.name = AttachmentName;
atch.parentId = lstBatchjob[0].Id;
atch.body = Blob.valueOf(finalstr);
insert atch;
}
}
else
{
finalstr = header + finalrecordString;
atch.contentType = 'text/plain';
atch.name = AttachmentName;
atch.parentId = lstBatchjob[0].Id;
atch.body = Blob.valueOf(finalstr);
insert atch;
}
}


}
}
global void Finish(Database.BatchableContext bc)
{
List<Attachment> ConsoliatedAttachmentFin = [Select Id,Name,Body from Attachment where Name =: AttachmentName order by LastModifiedDate desc limit 1];
if(ConsoliatedAttachmentFin.size()>0)
{
if(atch.Name==null){atch=ConsoliatedAttachmentFin[0];}
Messaging.EmailFileAttachment attach = new Messaging.EmailFileAttachment();
attach.setBody(atch.Body);
attach.setFileName('BatchJoblogs'+String.valueOf(System.today().adddays(-1)).removeEnd(' 00:00:00')+'.csv');
String[] receiverAddr=System.Label.Batch_Job_Email.split(',');
Messaging.SingleEmailMessage EmailWithAttachment = new Messaging.SingleEmailMessage();
EmailWithAttachment.setSubject('Batch Job Logs Are Attached '+ string.valueOf(System.today().adddays(-1)).removeEnd(' 00:00:00'));
EmailWithAttachment.setToAddresses(receiverAddr);
EmailWithAttachment.setPlainTextBody('Please find attached batch job logs');
EmailWithAttachment.setFileAttachments(new Messaging.EmailFileAttachment[]{Attach});
Id orgWideEmailId = [Select Id from OrgWideEmailAddress where DisplayName ='avi' limit 1].Id;
EmailWithAttachment.setOrgWideEmailAddressId(orgWideEmailId);
Messaging.SendEmailResult[] r= Messaging.sendEmail(new Messaging.SingleEmailMessage[]{EmailWithAttachment});

}
}

}

Step 6. Create Scheduler “BatchJobLogScheduler” for Batch job

global class BatchJobLogScheduler implements Schedulable {

global void Execute(SchedulableContext sc)
{
BatchJobLogs objBatch=new BatchJobLogs();
Database.executeBatch(objBatch);
}

}




Note : To get Output replace YESTERDAY with Today in Batch_Job_Log_Query

Output: to run Batch from Anonymous Window run below code.
BatchJobLogs objBatch=new BatchJobLogs();
Database.executeBatch(objBatch);

Open BatchJobLog Object Tab and see the Notes & Attachments related list.


Click on view link. Output as below


Email Output: