Common Apex Usage Patters

This articles details of some of the more common logging patterns.

Basic Apex Logging

Now that you're familiar with the basic philosophy of Pharos Triton, let's take a look at an example of apex logging. There are a number of ways to do logging ranging, from straightforward to very complex. We'll start with the basics and gradually move on to more advanced patterns and use cases.

In this scenario we'll take a look at a simple code snippet that performs a DML statement. The DML statement is wrapped into a try/catch block, where any potential exceptions can be handled. This scenario can take place anywhere: triggers, LWC Apex controllers, or even custom rest methods.

public void basicApexLogging() {
        Triton.instance.startTransaction();
	Triton.instance.debug(TritonTypes.Type.Backend,//type
			TritonTypes.Area.Accounts,//functional area
			'Apex logging example Pre-dml',//summary
			'Pre dml update. Processing account records'); //details 
	try {
		List<Account> accounts = [SELECT Id, Name FROM Account LIMIT 1];
		if (!accounts.isEmpty()) {
			Triton.instance.debug(TritonTypes.Type.Backend, 
					TritonTypes.Area.Accounts,   
					'Account records found!',
					'Pre dml update. Processing account records');		
			accounts[0].Name = 'Logging rules!';
			update accounts;
		}
	} catch (Exception e) {
		//uh-oh... we have an Exception on our hands. Let's log that!
		Triton.instance.error(TritonTypes.Area.Accounts, e);
	} finally {
		Triton.instance.stopTransaction();
	}
}

Let's take a closer look at this snippet. There are a few take aways in the code above:

  • The use of start/stopTransaction(). This initiates a new transaction context within Pharos and ensures that all subsequent logs are grouped under a single umbrella—more specifically, under the first log generated in the sequence. See the log structure detailed below.

If you have more logging to perform that you wish to group under the same umbrella, you can pass around the transaction Id (obtained from the Triton.instance.TRANSACTION_ID property). This would allow you to span across Salesforce transactions to trace a complex process.

  • Note the use of Type and Area values. You can check out the general guidelines here.

  • The use of debug() and error() methods. These simply provide a shorthand for creating log records with different categories, and different log levels. Note that different parameters are provided to debug() and error() methods.

  • The use of a finally{} construct. This ensures that stopTransaction() is the last method that executes in any event.

If you exceed a governor limit somewhere in your transaction, there's no guarantee that the finally{} block will execute, and with it the stopTransaction().

If stopTransaction() is not called, Pharos Triton simply stops logging under the parent log. In the example above, that poses no problem as there is no further logging after the flush().

Parent and Child Logs

Let's now assume that there is an exception raised during the DML operation. This will result in the following log records created:

  • A parent debug log generated on line (3)

    1. A child debug log generated on line (10)

    2. A child Apex error log generated on line (19)

      • An issue record will also automatically get created for this log. Issues, by default, are only created for error logs. Debug and other log categories such as Event or Warning do not generate issues by default. This behavior is customizable in the logging methods detailed here.

If no startTransaction() call is made Pharos Triton will simply create the logs without associating them together under a common parent. This would result in the log structure below.

  • A parent debug log generated on line (3)

  • A parent debug log generated on line (10)

  • A parent Apex error log generated on line (19)

    • An issue record will also automatically get created for this log. Similar to the example above. Issue creation behavior is not impacted by transactional logging.

Last updated