I have a simple Logger class with a static list of log objects and two methods. One method adds logs to the static list and the other method inserts the list. Right now I am manually calling the save logs method in a few different places. I was wondering if it is possible to have this method automatically called just before the Apex execution context finishes.
Rolling up comments.
Apex class itself is not executable. We would define methods and then call them independently depending on use cases. So if you have to log a particular execution context, that will the start/end of your method execution.
For your use cases:
I have a batchable class that adds logs throughout execution, then at the end of the execute method I call Logger.SaveLogs();. The second case it a webservice method where I call Logger.SaveLogs(); at the end of this method.
Fortunately batch class provides you a way to be able to log at the end when all batches have been executed. For this purpose, you can utilize the
finish() method of the batch class.
For other custom methods in custom classes, you current implementation is the only option. There's no equivalent of finish as available in batch classes, so you will need to make sure you log only when your method execution ends.
To log only at the end of a transaction requires knowing when the transaction ends.
- Batchable - by using
Database.Stateful, you can write to the persistent log in
- Queueable - write to the log at the end of
- Apex REST - write to log before returning a response
- Invocable Apex - write to log at end of static method
- Visualforce controller - Write to log at end of each action method you care about (like
- Schedulable - same as Queueable
- Apex Trigger - This can get tricky as knowing when the last trigger in the chain has executed is indeterminate as triggers can be invoked recursively such as through field updates (Workflow) or Process Builder record updates. Furthermore, if the trigger is not the initiation of the transaction, you might need to suppress any log initiation code (e.g. a VF controller doing DML - the trigger's code path is subsidiary to the transaction boundary defined by the VF action method. Also, a transaction can have more than 200 records and (except in Platform Event use cases, the trigger will get called more than once for each block of 200).
For triggers you could also consider establishing via a static variable a transaction context with a start datetime and name. Then use Platform Events to log out every loggable code unit including every trigger invocation's conclusion and have some other trigger subscribe to the Platform Events to re-assemble the trigger-scope logs into one large log covering the entire transaction scope (will need a scheduled job as well as knowing when the last trigger-scope log is complete is indeterminate.