Skip to content

Apex Observability Enhancements

Compare
Choose a tag to compare
@jongpie jongpie released this 29 Feb 18:15
· 38 commits to main since this release
5835da6

This release is a big one - and so is the description, to try to cover all of the changes.

Overview

This introduces some very powerful enhancements to improve the observability of Apex code, making it easier for Salesforce experts to answer questions like "what happened in my Apex code?" and "what did my Apex code look like?". It also takes some big steps towards streamlining the fields on LogEntry__c to simplify reporting, and shifting towards using custom LWCs to provide an improved user experience for viewing logging data.

Source Snippets

Nebula Logger now automatically logs a snippet of your Apex code, providing a snapshot of the relevant codeblock. These snippets are displayed in a very fancy code-viewer on the LogEntry__c page, using PrismJS

  • Origin Source Snippets: Any time you add a log entry in Apex, you will now be able to see a snippet of your Apex code that generated the LogEntry__c record.
  • Exception Source Snippets: Any time you include an Apex exception in your log entry, you will now also be able to see a snippet of Apex code that threw the exception.

For example, if you deploy the example Apex class below:

Example Class with Logging
public with sharing class ExampleClassWithLogging {
    public void doSomething() {
        Logger.finest('Starting the doSomething() method!');

        try {
            insertContact('Some Contact Name');
        } catch (Exception ex) {
            Logger.error('An unexpected exception occurred', ex);
            Logger.saveLog();
            throw ex;
        }
    }

    public Schema.Contact insertContact(String contactName) {
        Schema.Contact contact = new Schema.Contact();
        // TODO don't forget to populate the record's required fields
        // before deploying this code to prod!
        insert contact;
        return contact;
    }
}

...if you then run and run new ExampleClassWithLogging().doSomething();, Nebula Logger will generate a new LogEntry__c record with 2 code snippets - one snippet for the origin of the entry, and another snippet for the included exception.

image

In each snippet, you can see about 12 lines of source code that executed - the relevant line of code is automatically highlighted.

image

image

You can also click the 'View Full Source' button to see the entire Apex class or trigger that is currently deployed to the org. The modal even indicates if the source code has been modified since the LogEntry__c was generated, making it easy to know if the snippet on the LogEntry__c is still accurate.

image

image

Streamlined Reporting with New Origin & Exception Source Fields

Nebula Logger supports logging in 5 (5-ish) metadata types:

  • Apex classes
  • Apex triggers
  • Flows (and implicitly, Process Builder)
  • Lightning web components
  • Aura components

This release tries to provide a more consistent set of fields to use for reporting, regardless of which metadata type is using Nebula Logger.

Current State: LogEntry__c Fields Are Not Very Scalable

Originally when Nebula Logger was first created, Apex classes were the only focus - as new metadata types have been added over the years, new fields have also been added LogEntry__c that are specific to each metadata type. For example:

  • There are Apex class-specific fields like ApexClassName__c and ApexMethodName__c
  • There are Flow-specific fields like FlowActiveVersionId__c
  • There are Lightning component-specific fields like ComponentApiName__c and ComponentFunctionName__c

These approach has led to 2 challenges:

  • Field Limits. Each custom object in Salesforce has a limit on the number of custom fields, and this approach quickly eats up some of the limit for LogEntry__c.
  • Reporting. The current fields don't provide a consistent way to report on the data, you effectively have to use different sets of fields to report on each metadata type. This overcomplicates things for teams that want to monitor & report on support issues.

These challenges have created a cycle of new challenges & issues:

  • Not Scalable for Both Origin & Exception Metadata Sources The existing metadata-specific fields (like ApexClassName__c, FlowActiveVersionId__c, ComponentApiName__c, etc) are only for the log entry's origin (i.e., the metadata the generated the log entry). Due to concerns with field limits, there are not equivalent fields for exception details - arguably, it's more important to capture granular details about exceptions (instead of the origin), but the origin fields came first, and exception fields have never been added, which is a big gap in actionable data.
  • Not Scalable for All Supported Metadata Types The existing metadata-specific fields don't even cover all supported metadata types. Currently, Apex triggers aren't treated the same as the other metadata types. There are no trigger-specific fields, and most of Nebula Logger's codebase assumes "Apex code" == "Apex class". And while I think that triggers shouldn't contain logic (and thus, shouldn't really be doing any logging directly), the reality is that a lot of Salesforce orgs don't follow this best practice, and Nebula Logger should handle Apex triggers as effectively as it does Apex classes.

Future State: Scalable Exception & Origin Fields

To streamline things, this release introduces 2 sets of fields.

  • Origin Source fields - details about the source metadata that generated the log entry
  • Exception Source fields - details about the source metadata that generated the exception

Each set of fields consists of ~16 fields (about 16 Origin fields, and about 16 Exception fields). These fields are intended to work for all supported metadata types, which helps to simplify reporting, list views, etc.

The older, metadata-specific fields (like ApexClassName__c, FlowActiveVersionId__c, ComponentApiName__c, etc) will continue to be populated & supported for now, though it is likely that they will eventually be deprecated in the future.

LogEntry__c UI Changes

Overhauled the LogEntry__c flexipage LogEntryRecordPage

As the number of fields on LogEntry__c has grown, the complexity of the LogEntryRecordPage has also grown. This releases adds more tabs to the page's horizontal tab set.

image

Shifting To Custom LWCs for Nebula Logger's Record Pages

Nebula Logger heavily utilizies App Builder record pages (FlexiPage metadata) for displaying data in Log__c, LogEntry__c, etc - including heavy use of dynamic forms, conditional visibility, and some of the other amazing declarative features. However, there are several new & existing features that would benefit from custom UIs, and this release is the first step in adding new components that will improve the usefulness of the LogEntry__c page.

In particular, this release introduces a few new components, used to display Apex snippets with PrismJS. Other new components will be introduced over the coming months.

Core Unlocked Package Changes

New LogEntry__c Lighting Web Components (LWC)

  • logEntryMetadataViewer - Added a new component built specifically for the LogEntry__c object's record page. This LWC

New Helper Lighting Web Components (LWCs)

  • loggerCodeViewer - Added a new helper UI component that uses Prism JS to provide some very nice syntax highlighting & line numbers for displaying blocks of JSON and Apex code
  • loggerPageSection - Added a new helper UI component that provides a reusable way of implementing the lightning design system's "expandable section" component bluprint to mimic the functionality that the platform uses for native page layout sections

Updated Lighting Web Components (LWCs)

  • loggerHomeHeader - Updated to use the new helper LWC loggerPageSection to provide collapsible page sections in the View Environment Details modal
  • loggerSettings - Updated to use the new helper LWC loggerPageSection to provide collapsible page sections in the New/Edit settings modal
  • logViewer - Updated to use the new helper LWC loggerCodeViewer to display the Log__c record's JSON data

New LogEntryEvent__e Platform Event Fields

  • ExceptionLocation__c
  • ExceptionSourceActionName__c
  • ExceptionSourceApiName__c
  • ExceptionSourceMetadataType__c
  • OriginSourceActionName__c
  • OriginSourceApiName__c
  • OriginSourceMetadataType__c

New LogEntry__c Fields

The 3 permission sets LoggerLogViewer, and LoggerEndUser have been updated to have the relevant access to these new fields

  • 16 New 'Exception Source' fields
    • ExceptionLocation__c - this also includes a custom index, and is equivalent to the existing field OriginLocation__c.
    • ExceptionSourceActionName__c
    • ExceptionSourceApiName__c
    • ExceptionSourceApiVersion__c
    • ExceptionSourceCreatedById__c
    • ExceptionSourceCreatedByLink__c
    • ExceptionSourceCreatedByUsername__c
    • ExceptionSourceCreatedDate__c
    • ExceptionSourceId__c
    • ExceptionSourceLastModifiedById__c
    • ExceptionSourceLastModifiedByLink__c
    • ExceptionSourceLastModifiedByUsername__c
    • ExceptionSourceLastModifiedDate__c
    • ExceptionSourceMetadataType__c
    • ExceptionSourceSnippet__c
    • HasExceptionSourceSnippet__c
  • 15 New 'Origin Source' fields
    • OriginSourceActionName__c
    • OriginSourceApiName__c
    • OriginSourceApiVersion__c
    • OriginSourceCreatedById__c
    • OriginSourceCreatedByLink__c
    • OriginSourceCreatedByUsername__c
    • OriginSourceCreatedDate__c
    • OriginSourceId__c
    • OriginSourceLastModifiedById__c
    • OriginSourceLastModifiedByLink__c
    • OriginSourceLastModifiedByUsername__c
    • OriginSourceLastModifiedDate__c
    • OriginSourceMetadataType__c
    • OriginSourceSnippet__c
    • HasOriginSourceSnippet__c

New Apex Classes

  • LoggerStackTrace - this new class centralizes stack trace parsing for Apex & JavaScript stack traces, and makes it easy to reuse this logic for both the backend & frontend
  • LogEntryMetadataViewerController - this is a new controller class for the new LWC logEntryMetadataViewer, used to see code snippets for Apex classes & triggers

Updated Apex Classes

  • LogEntryEventBuilder now uses LoggerStackTrace for Apex stack trace parsing
  • ComponentLogger now uses LoggerStackTrace for JavaScript stack trace parsing
  • LogManagementDataSelector - Updated method getApexClasses() to include the Body field when querying ApexClass - Added new method getApexTriggers() to query ApexTrigger data
  • LogEntryHandler
    • Now also uses LoggerStackTrace to reconstitute a stack trace string into an instance of LoggerStackTrace to help with generating Apex code snippets
    • Now uses a new private inner class SourceMetadataSnippet to query a snippet of the ApexClass or ApexTrigger source that generated the LogEntry__c, as well as a snippet of the source that generated the LogEntry__c record's exception fields (ExceptionType__c, ExceptionMessage__c, and ExceptionStackTrace__c)

New LoggerParameter__mdt Record

  • Also added new LoggerParameter__mdt record QueryApexTriggerData.
    • When set to true (default), the ApexTrigger object is queried to get additional details about your Apex triggers
    • When set to false, the ApexTrigger will not be queried - any relevant fields on LogEntry__c will be null

New Static Resource LoggerResources

  • Added a new zip static resource, LoggerResources, that contains the JS & CSS files for PrismJS. If/when other files are needed in future releases, they'll be included in this same static resource.

Installation Info

Core Unlocked Package - no namespace

Full Changelog: v4.13.0...v4.13.1