LWC and Apex

In this article we'll describe the process for logging in LWC in conjunction with Apex. We will examine how Pharos associates two different types of logs together under a single umbrella.

Logging across LWC and Apex can be very helpful in both troubleshooting and profiling. The most common scenario is to track your component's UI logs and link these together with Apex action calls on the back end. This approach will allow you to see all LWC and Apex logs under the same parent log.

We'll assume that the start of our user flow originates from a button click (an LWC action) and then continues on the back end in Apex. Our goal is to link together the two types of logs. Let's begin with the LWC side.

LWC Component

Let's place a button in our component that will start the main execution and logging from a click event.

logDemo.html
<template>
    ....
    
    <lightning-button 
        variant="brand" 
        label="DML Error" 
        title="DML Error" 
        onclick={handleClick} 
        class="slds-m-left_x-small">
    </lightning-button>
    
    ....
</template>

LWC Controller

Now, let's take a look at our LWC controller and create our first log.

logDemo.js
//this apex action will generate a transaction Id on the back end 
//that will be used across js and apex
import getTransactionId from '@salesforce/apex/LogDemoController.getTransactionId';
//our apex action that will perform some logging
import apexActionThatGeneratesDMLError from '@salesforce/apex/LogDemoController.apexActionThatGeneratesDMLError';
//Triton logger component
import Triton from 'c/triton';
//import Triton enums 
import { AREA, TYPE } from 'c/triton';

export default class LogDemo extends LightningElement {

    tritonLogger;
    @track transactionId;
    
    connectedCallback() {
        this.tritonLogger = new Triton();
    }
    
    handleClick(event) {
        //note down some timing values for later
        this.startTime = performance.now();
        this.createdTimestamp = Date.now();
    
        //generate a transaction Id and start our UI execution
        getTransactionId({
        }).then((data) => {
            this.transactionId = data;
            this.executeScenario();
        }
    }
    
    executeScenario() {
        this.tritonLogger.debug(
            TYPE.FRONTEND, /* type */
            AREA.ACCOUNTS, /* functional area */
            'LWC action (from js) - DML Error', /* summary */
            'LWC action (from js) - DML Error - Execution Start', /* details */
            this.transactionId, /* transaction Id generated earlier */
            {name: 'TritonDemo', function: 'executeScenario'}, /* component info: name and function */
            performance.now() - this.startTime, /* duration of execution up to this point */
            this.createdTimestamp /* starting time of our execution */
        );
    
        //invoke our Apex action passing in the transaction Id 
        //for the apex controller to re-use
        apexActionThatGeneratesDMLError({
            transactionId: this.transactionId
        }).then(() => {
        }).catch((error) => {
            //log this exception
            this.tritonLogger.exception(error, null);
        });
    }

    ....
}    
    

The handleClick() method above will generate two LWC logs: one debug and one error log after the Apex action completes. Note that we are passing our generated transaction Id back to the Apex controller to use further during back-end logging.

Apex Controller

Next, let's look at our Apex controller. The action that we're calling from LWC is also doing some debug and error logging with the provided transaction Id.

LogDemoController.cls
public with sharing class LogDemoController {

//this method will use our logger to create a new transaction Id
@AuraEnabled
public static String getTransactionId() {
	return Triton.instance.startTransaction();
}

@AuraEnabled
public static void apexActionThatGeneratesDMLError(String transactionId) {
	//letting our logger know to re-use an existing transaction Id
	Log.instance.resumeTransaction(transactionId);
	Log.instance.debug(TritonTypes.Type.Backend, /* type */
			TritonTypes.Area.Community, /* functional area */
			'LWC controller (apex) - DML Error', /* summary */
			'LWC controller (apex) - DML Error - Apex Execution Start' /* details */
	);
	
	try {
		ContentVersion contentVersion = new ContentVersion();
		contentVersion.ContentLocation = 'Apex Error';
		contentVersion.Title = 'Apex Error';
		contentVersion.PathOnClient = 'ApexError.pdf';
		//this insert statement will generate a DMLException
		insert contentVersion;
	} catch (Exception e) {
		//let's log this exception
		Triton.instance.error(TritonTypes.Area.Community, e);
	}
}
....

}

Similar to our LWC controller, executing this action will result in a debug and an error log created.

The Result

Altogether, both LWC and Apex executions will generate the following log structure:

  • Parent LWC Debug Log from executeScenario(), line 34

    1. Child Apex Debug Log from our apexActionThatGeneratesDMLError() action, line 13

    2. Child Apex Error Log from our try/catch block inside the Apex action, line 38

The first log to get created within a sequence of logs using the same transaction Id automatically becomes the parent.

Last updated