Code Monkey home page Code Monkey logo

rflib's Introduction

Reliability Force

Build Status GitHub NPM package version codecov

The goal of this library is to help developers to create clean, production-ready code with a high level of operational supportability.

This library is inspired by Dan Appleman's (see Advanced Apex Programming) logging design pattern to collect better diagnostic information when dealing with errors in your Apex classes. This library expands his concepts to provide detailed log information from Lightning Components and Lightning Web Components, giving developers more visibility into the execution path on the client side, especially when dealing with production issues. The library can be configured to automatically report any unexpected errors through Salesforce's latest technologies such as Platform Events.

Key Features

The following lists describe some of the key features of rflib.

Logging Framework (package RFLIB):

  • Logger for LWC and Aura, which publishes logs the same way as Apex
  • Configuration through Custom Settings allowing for different log configurations between users
  • Aggregation of log statements when reporting
  • Using Platform Events for reporting of log statements
  • Masking of content in Log Messages
  • Log Archive using Big Objects
  • Automatically time and log execution duration
  • Dashboard for all Object, Field, and Apex/VF Page permissions for Profiles, Permission Sets, and Permission Set Groups
  • Supports Salesforce Functions (NodeJS only)
  • Supports logging in Flow and Process Builder
  • Supports OmniScript and Integration Procedures in OmniStudio
  • Display of platform details (Governor Limits, browser & NodeJS process details) for every Log Event
  • HTTP Request mocking framework to speed up integration development

Feature Switches (package RFLIB-FS):

  • Fully configured using Custom Metadata
  • Supports hierarchical structure (similar to Custom Settings) to override settings at the profile or user level
  • Fully supported in Flow Builder through Get Records or Apex Action

Trigger Framework (package RFLIB-TF):

  • Fully decoupled framework, trigger handlers work in isolation
  • Recursion tracking to allow for easy prevention of multiple executions
  • Fully configurable trigger management (activation, order, error handling, etc) using Custom Metadata Types
  • Framework for Retryable Actions using Platform Events for asynchronous actions with automatic retries

Deploy

The best way to add RFLIB to your environment is by installing the unlocked package.

Alternatively, you can either clone the repository and use 'sfdx force:source:deploy' to deploy this library to your Sandbox or use the Deploy to Salesforce button below to deploy it directly into your org.

Please check the CHANGELOG file for versions, install links and package aliases.

To install package via browser:

https://login.salesforce.com/packaging/installPackage.apexp?p0=<PACKAGE_VERSION_ID>

To install package via SFDX CLI Plugin (v2):

sf package install --package <Package ID> --target-org <your org alias>

Using the legacy CLI command:

sfdx force:package:install -p <Package ID> -w 10 -s AdminsOnly -u <your org alias>

To deploy code:

Deploy to Salesforce

To install the logger in a Salesforce Function using NodeJS:

npm install --save rflib

See the NPM Package Registry record for more details.

Documentation

Documentation such as "How To's" and more can be found in the Wiki of this repository.

Log Event Dashboard

Review any log events sent within the last 72 hours or receive new log events in real-time. The dashboard shows all the events and lets you filter them by searching text within the messages. This will make it easy to detect error codes or other log messages of value.

To enabled the Ops Center application, simply assign the Ops Center Access Permission Set to the users of your choice.

alt text

Permissions Explorer

Review object and field permissions for profiles and permission Sets easily within the same user interface. Many problems encountered in an org trace back to access issues. Using the Setup interface to review access for users is pretty inefficient. This dashboard provides access to all profiles and permissions and allows for quick filtering of the results.

To enabled the Ops Center application, simply assign the Ops Center Access Permission Set to the users of your choice.

alt text

Management Console

A critical aspect of operating a Salesforce Org is managing Governor Limits. There are transactional and org-wide limits, some of which RFLIB is consuming in order to report and display Log Events. While there are several different tools available to monitor org-wide Governor Limits, RFLIB provides a simple way to stay on top of those as well through the Management Console tab.

There, users with access to the Ops Center can view the current consumption of the org-wide Governor Limits relevant to RFLIB. In addition, RFLIB will display what users have not been provided with Permission Set to enable client logging and what users are assigned access to the Ops Center.

alt text

Application Event Dashboard

Whether a product owner wants to understand feature adoption or user behaviour, Application Events provide visibility into the an application's usage patterns and can help teams to make better decisions and learn more about their apps.

For operational teams, Application Events can be used to track integration requests and their outcomes, which can lead to a call to action to review RFLIB log messages for more details.

alt text

Updates

See CHANGELOG file for versions, install links and package IDs.

Credits

Attribution

rflib's People

Contributors

emregunel avatar j-fischer avatar kurtfairfield avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rflib's Issues

Download of log files broken in 3.0.1

Describe the bug
After installing version 3.0.1, downloading a log file in the Log Monitor does not work or throws an error in the UI (depending on whether Debug Mode is turned on). It complaints that this.createdById() is not a function.

Version
3.0.1 and 3.1

Code Snippets
N/A

Expected behavior
A text file should be downloaded when clicking the download button.

Additional context
This regression was introduced in version 3.0.1

Question - System Debug reduced for Trigger logger?

We are using both the trigger framework and Logger. In my org level settings, I have System Debug Log Level set to INFO. When running a test class, I have noticed that the data setup which fires a lot of triggers results in USER_DEBUG events in the log from logic in the various rflib trigger/feature switch classes even though it appears the respective log level of these statements is DEBUG.

Is this expected? Is there a way to suppress these DEBUG statements as my logs for a test execution are now mostly filled with Debug statements originating from the trigger and feature framework.

Licence mismatch

I've noticed the header licence on top of files are taken from some unrelated project:

Neither the name of mosquitto

...

Platforms events not firing

After installing it in a developer edition, because it is also not working on a Sandbox, I get no logs. I used the gitHub deploy button on a dev ed. Created the org level custom settings, added the permission set to my own user. I get no logs in the Log Monitor. Then I decide to do some debugging and it seems that the Platforms events are not firing. The permissions on "Log Events" are "Read" and "Create" on the profile. I activated debug logs for "Automated Process" entity and created a new event (snippet below) and I received nothing. I am clueless what I could be possible missing. I really appreciate your help here.

Version
Master branch

Code Snippets
rflib_Log_Event__e ev = new rflib_Log_Event__e(
Context__c ='',
Log_Level__c = 'DEBUG',
Log_Messages__c = 'test',
Platform_Info__c = 'info',
Request_ID__c = 'id'
);
EventBus.publish(ev);

Expected behavior
Logs in the Automated process. Log records in the log monitor.

Custom settings
Archive Log Level INFO
Batched Log Event Reporting Level NONE
Client Console Log Level INFO
Client Log Size 100
Client Server Log Level WARN
Email Log Level NONE
Enable Log Masking
Flush Log Cache Level NONE
Functions Compute Log Level DEBUG
Functions Log Size 100
Functions Server Log Level INFO
General Log Level INFO
Log Event Reporting Level INFO
Log Finalizer Class rflib_DefaultLogFinalizer
Log Size 100
Log Timer Class rflib_DefaultLogTimer
Logger Factory Class rflib_DefaultLoggerFactory
Org Wide Email Sender Address
System Debug Log Level DEBUG
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Provide mechanism to mask text in log messages

Is your feature request related to a problem? Please describe.
It is easy to log information that are considered sensitive, especially when logging entire records or query results. However, with the log events being published and possibly further processed, this could cause compliance issues. To protect against simple mistakes made by developers, some key information can be masked using rules identified by the user. With this rules, the log messages can be changed prior to publishing the log event.

Describe the solution you'd like
Create a CMT that will allow users to define rules for text replacements using regular expressions. There should be a option in the Logger Settings to enable masking, which will be set to false by default to allow for backwards compatibility. Once the option is enabled, the rules will be queried and applied in their configured order. The final string will be used for the Log Messages field in the Log Event.

Can this be done by combining existing functionality of RFLIB or Salesforce
No

Additional context
N/A

FeatureSwitchTest fails when there is a trigger on User

I had an issue with this test class. It seems that when the User is created and you have a trigger on the User object, the All_Triggers feature switch that comes with the trigger framework is evaluated. The process of evaluating that trigger does a get of directPublicGroupAssociations which then contains of groups of the user running the test.

The in tests that interrogate this (testGetAllScopedValues and testGroupSwitch) the absence of the setup associated group fails the test. I fixed this for myself by making the getter of directPublicGroupAssociations testVisible and setting it to null in these test classes inside the system.runas

The trigger framework be explicitly be mocked in this test class instead?

Originally posted by @mikbranchaud in #19 (comment)

Archive not populating in Sandboxes, but works in PROD with same settings...

Describe the bug
The Archive (big object) is not populating with records in a sandbox, even though cmdt settings are the same as in PROD which is working fine. But in sandbox, big object has no records in it at all, with Archive logging set to INFO.

Version
Was using 3.1.1, but upgraded to 4.0.0 (and 2.0.0 for both TS and FS successfully) problem persists in both versions.

Expected behavior
Archive should be populating.

Screenshots
image

Desktop (please complete the following information):

  • OS: W10
  • Browser Chrome
  • Version 103.0.5060.66

Additional context
Not sure what this is not working in the sandbox, but is working in PROD. All other sandboxes have same issue. Permission Set assigned to all users, with big object Logs Archive has Read and Create permissions. Perhaps there is some other configuration required in sandbox to make this work?

Package Dependency

Describe the bug
When going to install the most recent version of RFLIB-TF 1.1.0, with RFLIB-FS 2.3.0 installed (only package installed, no earlier usage) and has RFLIB code deployed from Andy in the Cloud tool. Get an error message.

` Invalid Upgrade. The package you're installing depends on package 'RFLIB-FS', version '1.0'. Install package 'RFLIB-FS' in the target org before you install package 'RFLIB_TF'.`

Version
Installing RFLIB-TF 1.1.0 with RFLIB-FS 2.3.0 already installed, no FS v1 installed ever.

Code Snippets
n/a

Expected behavior
package should have installed

Screenshots
see text msg above

Desktop (please complete the following information):

  • OS: W10Pro
  • Browser Chrome
  • Version current version

Smartphone (please complete the following information):
n/a

Additional context
all done in sandbox, trying a few other installation processes, maybe if I install FS v1 first then go to FS v2 after...

Issue with with reading reportingLogLevel from custom setting

reportingLogLevel = rflib_LogLevel.INFO.encompasses(newLevel) ? newLevel : rflib_LogLevel.INFO;

I've been playing around with this fantastic library for a client and I simply couldn't figure out why we need to encompass log levels for the reportingLogLevel and for the others we rely on the custom setting in the DefaultLogger class

I've updated my fork to read

reportingLogLevel = newLevel;

It's now working for me as I like it to. But I'm curious to understand why it's like that, to begin with.

Break the project into modules

Hi,

It would be cool if project was more clearly componentised. Maybe 4 different apps, or something. So that those of us, who like some of the features, but can't adopt others, can pick&choose.

Otherwise, great work.

Log Monitor not showing whole log data in namespace org

When I am using the log monitor in the developer org , the log data created is fine and completed. But when i am using log monitor in a namespace Org , the log data is not coming as whole. The script I am running is as follows :
rflib_Logger LOGGER = rflib_LoggerUtil.getFactory().createLogger('Demo class');
rflib_LogTimer logtimer = rflib_LoggerUtil.startLogTimer(LOGGER,300,'Handling Demo class');
try{
LOGGER.info('TRYING FINDING INPUT VALUES');
LOGGER.warn('Values and fields missing');
}
catch(Exception e){
LOGGER.error('Anonymous error occured',e);
}
logtimer.done();
I am attaching screenshots for both , if anyone has solution for it , please help.
capture 12
Capture
Capture 12 shows the namespace org data and capture shows the developer org data.

Report Platform Details in Log Events

Is your feature request related to a problem? Please describe.
While platform information are not critical in many situations when one reviews log messages, when they are those details are often missing. This means that one would have to update code to provide the details by adding Governor Limit information and deploy it before a deeper investigation can be done.
Having the information available could be valuable when debugging more challenging issues in any environment.

Describe the solution you'd like
RFLIB could track platform details behind the scene and add them to the Log Event platform event. Those could then be accessible in the Log Monitor for review. Ideally, those details should not take up much real-estate in the UI, since they are not commonly used.

Can this be done by combining existing functionality of RFLIB or Salesforce
While one could write those Limit details into many log statements, this approach takes a lot of work and is not intuitive.

Additional context
The feature will most likely include:

  • New field in the Log Event platform event
  • New field in the Log Archive big object
  • Update to the Apex default logger to prepare Governor Limit details for each Log Event
  • Update of the browser logger to include browser version details for each Log Event
  • Update of the Salesforce Function logger to include process information for Node
  • Update the Log Monitor to provide access to view these details

Trigger handlers for multiple objects in same transaction treated as Consecutive

Describe the bug
I have Trigger Handlers on two different objects, A and B. Handler A has DML on object B. When processing handler for Object A, rflib_TriggerManager.ACTIVE_HANDLER is set. When the DML on object B is executed, the rflib_TriggerManager
.runHandlers script skips the handler.run line since ACTIVE_HANDLER is not null and goes to handler.onConsecutiveRun.

Version
2.1. No

Code Snippets
private static rflib_TriggerHandler ACTIVE_HANDLER;
private static void runHandlers(rflib_TriggerManager.Args args, List handlers) {
for (TriggerHandlerInfo handlerInfo : handlers) {
rflib_TriggerHandler handler = handlerInfo.handler;

        LOGGER.debug('Is consecutive run? ' + (ACTIVE_HANDLER != null));

        if (ACTIVE_HANDLER == null) {
            try {
                ACTIVE_HANDLER = handler;
                handler.run(args);
            } catch (Exception ex) {
               //stuff
            } finally {
                ACTIVE_HANDLER = null;
            }
        }

        if (ACTIVE_HANDLER != null) {
            try {
                handler.onConsecutiveRun(args, incrementAndGetCounter(args));
            } catch (Exception ex) {
               //stuff
            }
        }
    }
}

Expected behavior
Our expectation is that onConsecutiveRun logic would be written to as actions to take on consecutive runs of the same handler, not a completely unrelated one. I would expect the ACTIVE_HANDLER to be a Map<string, rflib_TriggerHandler> where the string index is the handler class name.

Screenshots
If applicable, add screenshots to help explain your problem, i.e. Chrome Dev Console.

Desktop (please complete the following information):

  • OS: Windows
  • Browser n/a
  • Version n/a

Additional context
I understand that we could rewrite the onConsecutiveRun methods of all our handlers to run the functional logic but this would seem to reduce the value of having the framework in place. I am not sure if there is a value proposition for treating handlers across any object/operation as consecutive.

Created By filter for archived logs throws exception

Describe the bug
When filtering log events from the Logs Archive by the creator, a Javascript error (undefined) is thrown.

Version
RFLIB 3.0-3.2

Code Snippets
This is part of the Log Monitor components.

Expected behavior
Logs are filtered by the user ID, no error thrown.

Exception when Request.getCurrent().getRequestId() is null

Describe the bug
I have seen intermittent occasions where this line (rflib_DefaultLogger.reportLogs) errors:
Request_ID__c = requestId.substring(0, Math.min(requestId.length(), 40)),

with:
System.NullPointerException: Attempt to de-reference a null object

The first time it happened it was only in my sandbox and I made a temporary change to set Request_ID__c another way but just figured it was a fluke. This is now occurring in our shared dev environment so there seems to be some combination of circumstance that leads to this

Seems to only be occurring right now on one particular trigger which is on the User record (I dont remember the trigger this occurred on the first time)

Version
What version are you using? Did you make any modifications to the code?

Code Snippets
String requestId = Request.getCurrent().getRequestId();
rflib_Log_Event__e eventToLog = new rflib_Log_Event__e(
Request_ID__c = requestId.substring(0, Math.min(requestId.length(), 40)),
Log_Level__c = logLevel.toString(),
Context__c = context.substring(0, Math.min(context.length(), 40)),
Log_Messages__c = messageSize < MAX_MESSAGE_SIZE
? maskedLogMessagesIfApplicable
: maskedLogMessagesIfApplicable.substring(messageSize - MAX_MESSAGE_SIZE)
);

Expected behavior
I dont know why Request.getCurrent().getRequestId() would be null but if there is a setting I need to make to make it never null, or a backup to generate a unique Id on the occasion it is null

Screenshots
If applicable, add screenshots to help explain your problem, i.e. Chrome Dev Console.

Question on Email addresses used...

Wondering about the Custom Settings for Email...

Email Log Level : Defines what Log Events should be sent out to the Apex Exception Email list.

Org Wide Email Sender Address : Defines the email address to be used to send out the email notifications.

The first setting sets the threshold for when RFLIB log is emailed 'to the Apex Exception Email list'. Why then do we need another Email Address specified? Are their multiple email notification processes at work here, that required a different email address?

It looks to me that a copy of the logged message will then go to the entire Apex Exception Email list and the Org Wide Email specified as well?

I am running some tests, but thought I would ask the question as well.

Your thoughts?

Support Feature Switch assignments for Public Groups

Is your feature request related to a problem? Please describe.
Current hierarchy supports individual users and profiles, but sometimes it may be useful to assign feature switches to a subset of users of the same profile for testing purposes, i.e. A/B testing. Creating a config value per users is inefficient from a Feature Switch management perspective. Best way to solve this would be to create a Public Group in Salesforce and assign the value to that.

Describe the solution you'd like
Add Public Group as an option when selecting the scope. Feature Switches should be resolved in the following order:
Individual User -> Public Group -> Profile -> Global -> Default

Can this be done by combining existing functionality of RFLIB or Salesforce
No

Additional context
N/A

7 Dwarfs errors - potentially related to RFLIB Feature Switch CMDT call in validation rule...

Describe the bug
Getting intermittent Seven Dwarf errors (DOC, SLEEPY, GRUMPY) on unit tests in sandboxes, and now in PROD. SF Support is on the case...

appears to be associated with a Validation rule on custom object that checks a Feature Switch.

System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Validation Formula "Manage_PO_Status_Transitions" Invalid (common.exception.SfdcSqlException: ORA-30006: resource busy; acquire with WAIT timeout expired
ORA-06512: at "GRUMPY.CCUSTOMMETADATA", line 71
ORA-06512: at "GRUMPY.CCUSTOMMETADATA", line 92
ORA-06512: at line 1

SQLException while executing plsql statement: {call cCustomMetadata.lock_row_for_save(?)}(m021K000000KNqB)): []
Class.CSHandler_BlockDeactivationTest.testDataSetup: line 86, column 1

Version
2.3 (and 1.1 and 1.1), no mods

Code Snippets
validation rule call - $CustomMetadata.rflib_Feature_Switch__mdt.Allow_Any_PO_Status_Update.Turned_On__c

Expected behavior
no unit test errors

Screenshots
If applicable, add screenshots to help explain your problem, i.e. Chrome Dev Console.

Desktop (please complete the following information):

  • OS: [e.g. iOS] W10
  • Browser [e.g. chrome, safari] chrome
  • Version [e.g. 22] - Version 91.0.4472.124 (Official Build) (64-bit)

Additional context
intermittent, sometimes some tests fail, sometimes others don't

likely not an RFLIB bug (see what SF support says after checking the PROD server logs). I was just wondering if you had seen this before....

Client Log Size configuration setting is not changing the default value

Describe the bug
The Client Log Size setting does not take effect when changed, keeping the log size at the default size of 100.

Version
Affects all versions up until 3.0.1 (included).

Expected behavior
The client log size should change according to the setting.

Desktop (please complete the following information):

  • All OS, Browser versions

Smartphone (please complete the following information):

  • All OS, Browser versions

Mocking Triggers across multiple objects/operations during test

I think I see how your trigger test class mocks the trigger configuration mdt query locator so that a test method can anticipate one or more mock config records being narrowly executed for a single object/event. Could you comment on what the testing strategy would be if I am using a test data factory that creates multiple objects, each of which might have triggers on multiple events all in one command?

For instance, lets say I have a TestDataFactory method called createComplexCase which will spin out x cases, each related to 2 contacts each of which has some master detail records too. In my production environment, I would have before update, before insert, after update and after insert trigger handlers on Case and Contact. Lets say the Before Insert trigger on Case and the Before Insert trigger on Contact supports on functional feature, call it feature A, and the other trigger handlers support some unrelated features. So I have a test class FeatureA_Test which calls the TestDataFactory in a testSetup, but I dont want the triggers for FeatureB, C and D to execute. So I want to mock the config records from the FeatureA_Test testSetup method.

My understanding though is that the query locator is specific to an object type and event so I could mock the Case Before Insert config record by setting rflib_TriggerManager.QUERY_LOCATOR to a list of rflib_Trigger_Configuration__mdt I create. But when the TestDataFactory creates the contacts, the trigger handler I want to test on contact would not execute because I can only mock one object/type at a time. Is my understanding correct?

I think the answer is for a test class to pass a map of rflib_Trigger_Configuration__mdt indexed by object/event to the testdatafactory and for the testdatafactory to mock the config records dynamically before each DML statement. This would handle multiple objects but not multiple events. Thoughts?

rflib_DatabaseDmlExecutor code coverage

We use the --testlevel RunSpecifiedTests parameter in our CI/CD pipeline deployment setting with --runTests set to a list of each test class. This allows us to explicitly exclude certain long running tests so that our deployment job to our development/test stack can be optimized. Unfortuneately, using this parameter means that each individual class referenced must individually have 75% code coverage rather than a 75% average for the whole organization. We have accomplished this but while attempting to upgrade to the latest version of the logging framework, the introduction of the rflib_DatabaseDmlExecutor prevents us from maintaining this metric since it has 0% coverage.

Looking into the rflib_LogArchiveControllerTest class, testClearArchive_Success, I see that rflib_LogArchiveController.DML_EXECUTOR is mocked but I am not clear on the reasoning.

Unit Tests Failing

Describe the bug
All of a sudden, 12 RFLIB unit tests started failing in one of my orgs on NA154

Version
RFLIB 2.7 (unmodified)
RFLIB-FS 1.2 (unmodified)
RFLIB-TF 1.3 (unmodified)

Code Snippets

Error message: System.DmlException: Insert failed. First exception on row 0; first error: UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record: []
Stack trace: Class.rflib_UserFactory.Builder.persistWithPermissions: line 89, column 1 Class.rflib_UserFactory.insertWithCustomPermissionAndRetrieve: line 39, column 1 Class.rflib_TriggerManagerTest: line 42, column 1

Expected behavior
Day prior unit tests were fine, no significant metadata or data changes in the org, expect that they would keep passing

Stack trace shows error while trying to create a user with Standard User Profile, and the Custom Permission of Bypass All Triggers

Screenshots
From GearSet automated testing history

image

System Audit Trail showing before and after tests started failing - tests failed at 12:00 - 12:15 am PST on Oct 14, 2021

image

Installed Packages and dates

image

NA154 Server Maintenance Updates

image

Desktop (please complete the following information):

  • OS: - W10
  • Browser - Chrome
  • Version - 94.0.4606.81 (Official Build) (64-bit)

Smartphone (please complete the following information):
n/a

Additional context

Running daily unit testing in other org with different versioned RFLIB installed packages, no issues reported there.

RFLIB 2.3 (unmodified)
RFLIB-FS 1.1 (unmodified)
RFLIB-TF 1.1 (unmodified)

image

rflib_TriggerMangerTest.cls runs fine on its own from Intellij, but fails when run All tests from Dev Console (run async unchecked). Perhaps issue with synchronous running of tests.

This org is on a special Canadian AWS version, which is due to be swapped out to a Hyperforce Server on Oct 17, 2021, but has not happened yet.

Persistent storage with a custom object

Describe the solution you'd like
I'd like to persist the log entries in a custom object, for reporting, and production support.

Can this be done by combining existing functionality of RFLIB or Salesforce
Add a custom object (e.g. Application Log) that mirrors the data in the Log PE.
Add a Create Records action to the existing PB to save the PE data in this new object.
Add a Tab to the application to access the object in the UI.
Add a scheduled Apex job to delete old records from the log, driven by custom metadata.

Additional context
Performance reporting could also be enhanced by adding functionality to calculate the time difference between Log PE entries in a single transaction.
Log entry types could include "reporting" entries.

Added option to cap the creation of log events based on Governor Limits

Is your feature request related to a problem? Please describe.
Prevent RFLIB from exceeding Publish Immediate DML Limit by adding a configuration option to cap the number of events it would emit in favour of production needs.

Describe the solution you'd like
Update the default event publisher to cap the amount of events that would be emitted. The value should be able to change at runtime as well.

Can this be done by combining existing functionality of RFLIB or Salesforce
No

Additional context
N/A

Install Fails for RFLIB-FS 2.0.0 - due to Apex Compile Failure - workaround proposed

Describe the bug
Cannot install RFLIB-FS ver 2.0.0

Version
Installed RFLIB 4.0.0 successfully, trying to install RFLIB-FS 2.0.0

Expected behavior
should install

Screenshots
If applicable, add screenshots to help explain your problem, i.e. Chrome Dev Console.

Desktop (please complete the following information):

  • OS: W11
  • Browser Chrome
  • Version 103.0.5060.66

Additional context

Your request to install package "RFLIB-FS ver 2.0.0" was unsuccessful. None of the data or setup information in your salesforce.com organization was affected.

If your install continues to fail, contact Salesforce CRM Support through your normal channels and provide the following information.

Organization: redacted (00D0r0000008dbo)
User: redacted (0051K000008fbLK)
Package: RFLIB-FS (04t3h000004sq5x)

Problem:

1.  Apex compile failure
Apex class rflib_TriggerManagerTest: line 42, column 47: Variable does not exist: rflib_UserFactory

2.  Apex compile failure
Apex class rflib_TriggerManagerTest: line 43, column 54: Variable does not exist: rflib_UserFactory

Workaround

Selecting the option to not compile all Apex classes works to allow the installation. Wanted to make sure this was a viable workaround, or perhaps is even best practice. But as I do not fully understand the root cause of why this is a blocking issue for install, thought I would ask the questions.

image

Flush LOG_STATEMENTS after reporting?

I'm wondering why we don't flush the LOG_STATEMENTS list after reporting it?
There might be a time where I want to fire 2 warns, and they end up building a stack across the events?

rflib_Logger LOGGER =rflib_DefaultLogger.create('My Super Cool Context');
LOGGER.warn('warn  ' + '\n' + ' I am a message body that had new lines in it');
LOGGER.warn('warn2');

Something like above will give me two platform events
image

Describe the solution you'd like
Let's flush the log out after we've had a successful event?

System.debug(LoggingLevel.ERROR, JSON.serialize(result.getErrors()));

public class PlatformEventPublisher implements EventPublisher {
    public void publish(rflib_Log_Event__e event) {
      Database.SaveResult result = EventBus.publish(event);     
      if(!result.isSuccess()) {
        System.debug(LoggingLevel.ERROR, JSON.serialize(result.getErrors()));
      }
// FLUSH here, maybe?
    }
  }

Can this be done by combining existing functionality of RFLIB or Salesforce
Am I missing a design reason for this? Would I just make my own logger implementing rflib_Logger myself, and not influence the default logger?
Was it expected to just use createBatchedLogger if I wanted this functionality?

Main reason for calling this out here is I don't want instantly split my own fork far away from base rflib.

Clearing the Log Archive in RFLIB 3.0.0 does not work

Describe the bug
Trying to clear the log archive does not work.

Version
3.0 - no modifications

Code Snippets
N/A - Log Monitor Dashboard functionality

Expected behavior
Logs in Archive are cleared.

Screenshots
N/A

Additional context
There is no server request being made and running the controller code anonymously fails with an error that the CreatedDate__c cannot be sorted in ascending order.

Better Error Reporting When a Trigger Handler Class Doesn't Exist

Is your feature request related to a problem? Please describe.
When a Trigger Handler class referenced by a Trigger Configuration record doesn't exist, a NullPointerException is thrown. It's not immediately apparent that the cause is because a class is missing, and once that is determined to be the root cause, it can take some time to figure out which one is missing.

Describe the solution you'd like
Two possible solutions:

  1. A runtime check that the class exists before trying to instantiate it and an informative error log if it doesn't. This could be done by querying the ApexClass object, or just checking if the Type is not null before instantiating it.

Type handlerType = Type.forName(handlerInfo.Class_Name__c);
rflib_TriggerHandler handler = (rflib_TriggerHandler) handlerType.newInstance();

  1. A unit test that queries existing classes and cross-references them against the classes referenced in the Trigger Configuration records. Less effective as unit tests may not always be run prior to the trigger being invoked.

Provide way to track execution time and log a messages if a threshold is exceeded

RFLIB will introduce the concept of a Log Timer. This utility class allows to track the time between instantiation and the invocation of a done() method, which will stop the time and, based on a defined threshold, log a message if said threshold was exceeded.

The following code snippets show how the feature would be used:

// in LWC:

import createLogger, createLogTimer from 'rflibLogger'

let timer = createLogTimer(logger, 500, 'Action invocation');
// ...
timer.done();

/* END */
// In Aura:

// cmp
<c:rflibLogger aura:id="loggerFactory" />

// controller or helper
var loggerFactory = component.find('loggerFactory');
var timer =  loggerFactory.createLogTimer(logger, 500, 'Action invocation');

timer.done();

/* END */ 
// In Apex:
rflib_LogTimer logTimer =  rflib_LoggerUtil.createLogTimer(logger, 500, 'action invocation');

logTimer.done()

RFLIB will provide a default implementation, however, it will use the same dependency injection mechanism to allow for a different implementation to be used.

Does logger need to be declared as static?

Is your feature request related to a problem? Please describe.

Looking for some clarification here. In all you example code, you instantiate a logger class as static, always from what I could see. So I copy the pattern and declare all logger static.

But when I instantiate a static logger instance on an Apex defined type that is used in a Screen Flow, the flow engine breaks hard. Change it to non-static, and no issues. The Apex defined type really does not need any logging, I just am following your best practices and putting a logger instance in all classes. This Apex defined type is used a Data Transfer Object (DTO) to hand complex data structure between the flow and invocable actions.

Describe the solution you'd like

Just want to know if a non-static logger instance is a viable usage, and if not can you give me a brief explanation why? I had a look at the code base, but could not find any reason it should/must be static, except maybe to be more efficient?

Can this be done by combining existing functionality of RFLIB or Salesforce

Yes, I think it works just fine as non-static declaration

Additional context

Here is the class usage... removing 'static' from line 14 solves all my Screen Flow errors.

image

Here is the ugly Screen Flow error - no logs are created about this error in FLOW or in the debug logs...

image

image

Cannot get trigger on rflib_Log_Event__e to fire within unit test

Contextual Description
I have an error diagnostics framework I am about to deploy that uses RFLIB to allow flows to create RFLIB error log records using the Apex action, but then, in the case of flows centering on a particular custom object, intercepts those log events, and converts them into an error record based on a child custom object that gets attached to the original custom object record.

Part of this framework is an Apex trigger that is supposed to fire after insert on the rflib_Log_Event__e object. But whatever I do, it seems that I cannot get this trigger to fire. Or if it is firing, the coverage numbers don't show that the trigger is getting covered, so I might not be able to deploy it. That's what I am afraid of. More details are provided below.

Version
I am using RFLIB 4.1.0, and I have made no modifications to any of the code.

Code Snippets
I have tried a couple of different ways to create an ERROR log event, as follows:

  1. Using the logger
        final String CONTEXT = 'Context';
        rflib_Logger logger = rflib_LoggerUtil.getFactory().createLogger(CONTEXT);
        final String PSR_ID = testPsr.Id; // test record created earlier
        final String MESSAGE = 'Cry havoc and let slip the dogs of war';
        logger.error('[{0}] {1}', new List<Object> { PSR_ID, MESSAGE });
  1. Publishing the platform event directly
        rflib_Log_Event__e testEvent = new rflib_Log_Event__e(
            Context__c = CONTEXT,
            Log_Level__c = 'ERROR',
            Log_Messages__c = '['+PSR_ID+'] '+MESSAGE
        );
        EventBus.publish(testEvent);

The trigger that I am trying to cover in the unit test looks like this:

trigger LogEventTrigger on rflib_Log_Event__e (after insert) {
    LogEventHandler handler = new LogEventHandler();
    handler.handleEvents(Trigger.new);
}

Expected behavior
Either as a result of either publishing an instance of rflib_Log_Event__e directly to the event bus, or as a result of using the logger to log an event with a log level of ERROR, I would have expected the trigger to fire. But it never does. However, it must be firing in normal operation outside of unit tests, because it is creating the custom error child records and attaching them to the parent custom object records just fine, exactly as expected. So the trigger must be firing under "normal" circumstances as opposed to in a unit test. Of course, if I can never get this trigger to fire in a unit test context, I won't be able to deploy it, and that could be a disaster since it's an essential part of the whole error handling edifice I have build up over several weeks of sandbox-based development. Incidentally, since this seems to be related to the environment in which the code is running, I have tried the unit tests with both SeeAllData=true and SeeAllData=false, but it does not appear to make any difference.

Desktop

  • OS: macOS Ventura version 13.2.1
  • I am not testing via the browser, but in my IDE
  • The IDE is IntelliJ 2022.3 running the (very excellent) Illuminated Cloud plugin for Salesforce development, version 2.2.5.0
  • The coverage results display that shows no coverage of the trigger is integrated with the IDE. Here is a screenshot of the trigger code with a red strip next to it, meaning no coverage.

image

Questions on RFLIB CMDT record manipulation in test and declarative contexts...

As both the RFLIB Feature Switch and Trigger Method activation/deactivation are configured via custom metadata records, I wondered if you had a best practice pattern to manipulate these programmatically, in unit testing for example?

While handy, CMDT records are non-writeable in test context, so what I typically do for CMDT in Apex is wrap the call to the CMDT in a test-visible wrapper class, as per these examples. But I am not sure this will work with the CMDT in RFLIB, without modifying the package code, but maybe I am missing something.

https://www.forcetalks.com/blog/custom-metadata-test-class-coverage-in-salesforce/
https://www.avenga.com/magazine/salesforce-custom-metadata/

While I don't love this confusing pattern, it is the only solution I have come across to resolve the non-test-context-writeable CMDT issue in Salesforce.

My questions are these:

  1. Is there a way to manipulate the CDMT records in test context built into RFLIB that I am overlooking?
  2. Is there a way to achieve similar control in declarative usages, for instance when an RFLIB Feature Switch is called from an SObject Validation rule?

Your thoughts?

Log Events Not Published

Describe the bug
While it works on all our sandboxes, .info / .warn / .error / .debug statements in Production do not generate a Log Platform Event. There doesn't seem to be an issue with Log Platform Event publishing itself: I was able to publish an event "manually" (creating the Event and invoking EventBus.publish), and it showed up in the Log Monitor.

Version
V4 - no modifications.

Code Snippets
`rflib_Logger LOGGER = rflib_LoggerUtil.getFactory().createLogger('testlogger');

LOGGER.info('hi');`

Expected behavior
A Log Event should be published.

Screenshots
If applicable, add screenshots to help explain your problem, i.e. Chrome Dev Console.

Additional context
Batched Log Event Reporting Level INFO
Client Console Log Level NONE
Client Log Size 100
Client Server Log Level INFO
Email Log Level NONE
Enable Log Masking Not Checked
Flush Log Cache Level INFO
Functions Compute Log Level DEBUG
Functions Log Size 100
Functions Server Log Level WARN
General Log Level DEBUG
Log Event Reporting Level INFO
Log Finalizer Class rflib_DefaultLogFinalizer
Log Size 1
Log Timer Class rflib_DefaultLogTimer
Logger Factory Class rflib_DefaultLoggerFactory
Org Wide Email Sender Address
System Debug Log Level DEBUG

Link log entries to a record id

I would like to be able to quickly search log for a particular Id, usually a Case Id for my project. This is somewhat easy in the platform event monitor component (though it can sometimes take a long time for all the entries from the past three days to load into the component). But if the original issue occurred more than 72 hours in the past and we want to troubleshoot the root cause without reproducing the issue (frequently reproducing the issue has side affects we want to avoid) then we would need to search the archive log in the Message attribute (assuming we consistently put the record id in the message

It would be nice if the LOGGER.() call optionally accepted a record id which was populated in its own field on the archive big object. I could then query by this column directly. I could also create a related list (not sure if a custom what id can be configred which would be supported by the new dynamic related list feature but we have a custom related list aura component that will just run any soql to filter a list which we could use to filter by the record page reccord id)

Log Level for Exceptions in a "Catch Exception" Trigger Handler

When a trigger handler has a Catch Exception configuration, the log that gets created has a level of WARN. I would like to propose that it be changed to a level of ERROR, just like an Abort Transaction configuration.

It seems to me that even if the handler is configured for the exception to be caught, an exception occurring in the handler is still definitely an error scenario, even if the other handlers continue to execute. Open to hearing reasoning behind the current WARN level though!

I recently had a trigger handler for a platform event configured as Catch Exception—it was failing, but since Error Emails were configured to go out only at a level of WARN, I didn't get notified, and I had to dig a bit to find the warning log.

Minor Issue : BEM Notification Deprecating -- in CSS in the Summer '21 release

Read this in the W22 Dev Maintenance module, and wondered if this had any impact on RFLIB.

From - W22 Dev Maintenance Trailhead Module

BEM Notation with Double Dashes Is Being Deprecated
The BEM notation with double dashes (--) in Lightning Design System will be deprecated in Summer ’21 and replaced by the single underscore notation (_).

Why: Double dashes are not supported in XML files that include comments. This notation change was first announced in Salesforce Lightning Design System (SLDS) Release 2.3.1 on May 25, 2017, and announced again in the Winter ’21 release notes.

How: In Summer ’21, all BEM notation with double dashes will no longer be available in SLDS 2.13.0 and later versions. For your styles to continue working with SLDS 2.13.0 and later versions, replace -- with _ in your CSS. For example, replace slds-button--brand with slds-button_brand. If you’re using SLDS 2.12.2 and earlier versions, your styles continue to work as no changes have been made to those versions.

If you develop using VSCode, use the SLDS Validator extension to fix the BEM notation in your code. The extension is available as a standalone but also as part of the Salesforce Extension Pack.

I notice there is a bit of double dash notation in rflibLogEventList.css, not sure if this deprecation is applicable here or just for SLDS specific tags only, but thought I would mention it in case. Better to know before...

 .selected {
    background-color: var(--lwc-colorBackgroundRowNew);
}

.slds-table_striped tbody tr:nth-of-type(even).selected > td {
    background-color: var(--lwc-colorBackgroundRowNew);
 }

PlatformEventSubscriberConfig to avoid need for Org-wide Email?

Is your feature request related to a problem? Please describe.
It's annoying to have to configure an org-wide email address for alert emails to be able to be sent out. Also not ideal that the email has to be available to all profiles.

Describe the solution you'd like
The PlatformEventSubscriberConfig might be a way to avoid the need for an org-wide email. I haven't tested it so I could be wrong...

I also imagine it would come with some setup on the admin's part since it is tied to a user in the org, has no user interface for configuration, and I'm unsure if it is packageable.

Additional context
Some good info on PlatformEventSubscriberConfig https://salesforce.stackexchange.com/questions/357570/how-do-i-change-the-running-user-of-a-platform-event-trigger-handler

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.