[SalesForce] custom error logging, batch apex, failure/success counts

This may be simple, but I want to implement custom error logging for a batch class, where handled exceptions get written to a logging object in the database.

So I could use the technique in Andrew's answer here: Can I prevent an insert to be rolled back even if my class (later) runs into an exception?

The wrinkle is that if a handled exception occurs and is logged, I'd still like that batch to count as a "Failure" so that when the user monitors the job in Apex Jobs, it'll still show in the failed batches count.

enter image description here

Make sense? I'm handling the exceptions in this case in order to log them, not because I want them hidden from the user.

Is it possible to do this, and still have the log survive? If I use Andrew's technique, and catch the original err, do a rollback, write the logs, and then throw a new exception, it'll roll back the logs, right? And if I don't do the throw, the batch will count as a success, right?

Best Answer

Yes, you can capture your logs and still have individual batches fail and rollback. For that you need to define an instance variable in your batch class - List of custom object used for logging - to store your logs while batch is running and insert them all at once in the finish() method. You will have to add Database.Stateful to your class definition (see 'Using State in Batch Apex' in this document) to ensure that your instance variable is preserved across transactions.

global class TestBatch implements Database.Batchable<sObject>, Database.Stateful {

    global List<Log__c> logs;

    global TestBatch() {
        logs = new List<Log__c>();
    }

    global Database.QueryLocator start(Database.BatchableContext BC) {
        query = 'Your query...';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope) {
        for (sobject s : scope) {
            try{
                Your logic goes here...
            } catch (Exception e) {
                logs.add(new Log__c(
                        Name__c = '...',
                        Stacktrace__c = e.getStackTraceString()
                    ));
                throw e;
            }
        }
        update scope;
    }

    global void finish(Database.BatchableContext BC) {
        insert logs;
    }
}
Related Topic