Skip to content

Commit

Permalink
v1.6.15 - Continued Bulk Full Recalc Work (#566)
Browse files Browse the repository at this point in the history
* Standardizes prefixing System namespace for logging levels, which was inconsistent
* updates polling time in Full Recalc app from 3 seconds to 10 seconds between polls to minimize number of logs produced while waiting for full recalcs to finish
* fixes an inconsistency across batch full recalc runs where state tracking could fail if parents present in disparate batch chunks - say, chunks 1, 3, 5, etc... - had children qualify in only some of those batches. This has been a complicated and pernicious issue, and in many ways is a return to some prior version of the parent tracking present in prior versions of Apex Rollup. I've added some logging to the end of each batch chunk to monitor how this affects LDV orgs
  • Loading branch information
jamessimone authored Feb 23, 2024
1 parent 7270aa9 commit 403fa58
Show file tree
Hide file tree
Showing 31 changed files with 162 additions and 146 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ As well, don't miss [the Wiki](../../wiki), which includes even more info for co

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaYrAAK">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaZ6AAK">
<img alt="Deploy to Salesforce"
src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaYrAAK">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaZ6AAK">
<img alt="Deploy to Salesforce Sandbox"
src="./media/deploy-package-to-sandbox.png">
</a>
Expand Down Expand Up @@ -1020,8 +1020,8 @@ You have several options for custom logging plugins for Rollup (all Rollup Plugi
public class RollupLogger {

public interface ILogger {
void log(String logString, LoggingLevel logLevel);
void log(String logString, Object logObject, LoggingLevel logLevel);
void log(String logString, System.LoggingLevel logLevel);
void log(String logString, Object logObject, System.LoggingLevel logLevel);
void save();
}
}
Expand All @@ -1030,7 +1030,7 @@ public class RollupLogger {

You can implement `RollupLogger.ILogger` with your own code and specify that class name in the `Rollup Plugin` CMDT records. _Alternatively_, you can also _extend_ `RollupLogger` itself and override its own logging methods; this gives you the benefit of built-in message formatting through the use of the protected method `getLogStringFromObject`, found in `RollupLogger.cls`. For more info, refer to that class and its methods. Either way, the API name for the CMDT record **must** include `Logger` in order to work (eg: `RollupCustomObjectLogger`, `RollupNebulaLoggerAdapter`).

You can use the included `Rollup Plugin Parameter` CMDT record `Logging Debug Level` to fine-tune the logging level you'd like to use when making use of Apex debug logs (from method #3, above). Valid entries conform to the `LoggingLevel` enum: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST. FINEST provides the highest level of detail; ERROR provides the least. INFO will provide a high-level overview, while DEBUG will contain data about individual parent records being rolled up. The granularity of the data logged will continue to get finer as you move towards FINEST as the logging level.
You can use the included `Rollup Plugin Parameter` CMDT record `Logging Debug Level` to fine-tune the logging level you'd like to use when making use of Apex debug logs (from method #3, above). Valid entries conform to the `System.LoggingLevel` enum: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST. FINEST provides the highest level of detail; ERROR provides the least. INFO will provide a high-level overview, while DEBUG will contain data about individual parent records being rolled up. The granularity of the data logged will continue to get finer as you move towards FINEST as the logging level.

### Other Rollup Plugins

Expand Down
18 changes: 9 additions & 9 deletions extra-tests/classes/RollupLoggerTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ private class RollupLoggerTests {
static void shouldLogUsingCustomLoggerWhenSupplied() {
setup();

RollupLogger.Instance.log('hi', LoggingLevel.DEBUG);
RollupLogger.Instance.log('hi', System.LoggingLevel.DEBUG);

System.assertEquals('hi', locallogString);
System.assertEquals(LoggingLevel.DEBUG, localLogLevel);
System.assertEquals(System.LoggingLevel.DEBUG, localLogLevel);
}

@IsTest
static void shouldLogCustomObjectWhenSupplied() {
setup();
Account acc = new Account();

RollupLogger.Instance.log('hello', acc, LoggingLevel.FINE);
RollupLogger.Instance.log('hello', acc, System.LoggingLevel.FINE);

System.assertEquals('hello', locallogString);
System.assertEquals(acc, localLogObject);
System.assertEquals(LoggingLevel.FINE, localLogLevel);
System.assertEquals(System.LoggingLevel.FINE, localLogLevel);
}

@IsTest
Expand Down Expand Up @@ -61,15 +61,15 @@ private class RollupLoggerTests {
Rollup.defaultControl = new RollupControl__mdt(IsRollupLoggingEnabled__c = false);
RollupPlugin.pluginMocks = new List<RollupPlugin__mdt>{ new RollupPlugin__mdt(DeveloperName = ControlUpdatingLogger.class.getName()) };

RollupLogger.Instance.log('Should not be logged', LoggingLevel.DEBUG);
RollupLogger.Instance.log('Should not be logged', System.LoggingLevel.DEBUG);
System.assertEquals('logging isn\'t enabled, no further output', localLogString);

RollupLogger.Instance.updateRollupControl(new RollupControl__mdt(IsRollupLoggingEnabled__c = true));
String expectedLogMessage = 'hi';
RollupLogger.Instance.log(expectedLogMessage, LoggingLevel.INFO);
RollupLogger.Instance.log(expectedLogMessage, System.LoggingLevel.INFO);

System.assertEquals(expectedLogMessage, localLogString);
System.assertEquals(LoggingLevel.INFO, localLogLevel);
System.assertEquals(System.LoggingLevel.INFO, localLogLevel);
}

private static void setup() {
Expand All @@ -79,11 +79,11 @@ private class RollupLoggerTests {

// Type.forName requires public visibility
public class ExampleLogger implements RollupLogger.ILogger {
public void log(String logString, LoggingLevel logLevel) {
public void log(String logString, System.LoggingLevel logLevel) {
locallogString = logString;
localLogLevel = logLevel;
}
public void log(String logString, Object logObject, LoggingLevel logLevel) {
public void log(String logString, Object logObject, System.LoggingLevel logLevel) {
locallogString = logString;
localLogObject = logObject;
localLogLevel = logLevel;
Expand Down
2 changes: 1 addition & 1 deletion extra-tests/classes/RollupTestUtils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class RollupTestUtils {
public class DMLMock extends RollupSObjectUpdater {
public List<SObject> Records = new List<SObject>();
public override void doUpdate(List<SObject> recordsToUpdate) {
RollupLogger.Instance.log('mock received the following for update:', recordsToUpdate, LoggingLevel.DEBUG);
RollupLogger.Instance.log('mock received the following for update:', recordsToUpdate, System.LoggingLevel.DEBUG);
this.Records = recordsToUpdate;
}
}
Expand Down
12 changes: 6 additions & 6 deletions extra-tests/classes/RollupTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -1749,30 +1749,30 @@ private class RollupTests {
static void shouldPassRecalcValueForConcatDistinct() {
rollupOp = Rollup.Op.CONCAT_DISTINCT;
RollupCalculator.Factory = new FactoryMock();
RollupTestUtils.loadAccountIdMock(new List<ContactPointAddress>{ new ContactPointAddress(PreferenceRank = 5) });
RollupTestUtils.DMLMock mock = RollupTestUtils.loadAccountIdMock(new List<ContactPointAddress>{ new ContactPointAddress(Name = 'Hi', PreferenceRank = 5) });
Rollup.apexContext = TriggerOperation.AFTER_INSERT;

Test.startTest();
Rollup.concatDistinctFromApex(ContactPointAddress.PreferenceRank, ContactPointAddress.ParentId, Account.Id, Account.AnnualRevenue, Account.SObjectType, 'a')
.runCalc();
Rollup.concatDistinctFromApex(ContactPointAddress.Name, ContactPointAddress.ParentId, Account.Id, Account.Description, Account.SObjectType, 'a').runCalc();
Test.stopTest();

System.assertEquals('a', testMetadata.FullRecalculationDefaultStringValue__c);
System.assertEquals('a', mock.Records.get(0).get(Account.Description));
}

@IsTest
static void shouldPassRecalcValueForConcat() {
rollupOp = Rollup.Op.CONCAT;
RollupCalculator.Factory = new FactoryMock();
RollupTestUtils.loadAccountIdMock(new List<ContactPointAddress>{ new ContactPointAddress(PreferenceRank = 5) });
RollupTestUtils.DMLMock mock = RollupTestUtils.loadAccountIdMock(new List<ContactPointAddress>{ new ContactPointAddress(Name = 'Hi', PreferenceRank = 5) });
Rollup.apexContext = TriggerOperation.AFTER_INSERT;

Test.startTest();
Rollup.concatFromApex(ContactPointAddress.PreferenceRank, ContactPointAddress.ParentId, Account.Id, Account.AnnualRevenue, Account.SObjectType, 'a')
.runCalc();
Rollup.concatFromApex(ContactPointAddress.Name, ContactPointAddress.ParentId, Account.Id, Account.Description, Account.SObjectType, 'a').runCalc();
Test.stopTest();

System.assertEquals('a', testMetadata.FullRecalculationDefaultStringValue__c);
System.assertEquals('a', mock.Records.get(0).get(Account.Description));
}

@IsTest
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apex-rollup",
"version": "1.6.14",
"version": "1.6.15",
"description": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion plugins/CustomObjectRollupLogger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ To install this plugin and get it setup within your org properly:
2. Navigate to the Rollup Plugin CMDT (Setup -> Custom Metadata Types -> Manage Records next to Rollup Plugin -> New)
3. (This should already be done for you, upon install, but always good to double-check) - Enter `RollupCustomObjectLogger` into the `Rollup Plugin Name` field, choose the `Org_Default` rollup control record (and ensure `Is Rollup Logging Enabled?` is checked off on that record); the label can be whatever you'd like

That's it! Logs will now start flowing through on all rollup operations to `RollupLog__c`. A permission set, `Rollup Log Viewer` is included so that you can grant Rollup Log access to users other than yourself (should you be so inclined). You can use the included `Rollup Plugin Parameter` CMDT record `Custom Logging Debug Level` to fine-tune the logging level you'd like to use. Valid entries conform to the `LoggingLevel` enum: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST. FINEST provides the highest level of detail; ERROR provides the least.
That's it! Logs will now start flowing through on all rollup operations to `RollupLog__c`. A permission set, `Rollup Log Viewer` is included so that you can grant Rollup Log access to users other than yourself (should you be so inclined). You can use the included `Rollup Plugin Parameter` CMDT record `Custom Logging Debug Level` to fine-tune the logging level you'd like to use. Valid entries conform to the `System.LoggingLevel` enum: ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST. FINEST provides the highest level of detail; ERROR provides the least.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class RollupCustomObjectLogger extends RollupLogger {
this.rollupLogEvents.clear();
}

protected override void innerLog(String logString, Object logObject, LoggingLevel logLevel) {
protected override void innerLog(String logString, Object logObject, System.LoggingLevel logLevel) {
logString = this.getBaseLoggingMessage() + logString + '\n' + this.getLogStringFromObject(logObject);
if (logString.length() >= MAX_LENGTH) {
// normally we could do this with the AllowFieldTruncation property on Database.DMLOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ global without sharing class RollupLogBatchPurger implements Database.Batchable<
}

public void finish(Database.BatchableContext bc) {
RollupLogger.Instance.log('RollupLogBatchPurger finishing up after having deleted ' + this.recordCount + ' rollup logs', LoggingLevel.DEBUG);
RollupLogger.Instance.log('RollupLogBatchPurger finishing up after having deleted ' + this.recordCount + ' rollup logs', System.LoggingLevel.DEBUG);

String orphanedLogsQuery = 'SELECT Count() FROM RollupLog__c WHERE NumberOfLogEntries__c = 0 AND IsDeleted = false';
if (Database.countQuery(orphanedLogsQuery) > 0 && this.hasDeletedOrphanedLogs == false) {
orphanedLogsQuery = orphanedLogsQuery.replace('Count()', 'Id');
this.hasDeletedOrphanedLogs = true;
RollupLogger.Instance.log('Deleting orphaned logs ...', LoggingLevel.DEBUG);
RollupLogger.Instance.log('Deleting orphaned logs ...', System.LoggingLevel.DEBUG);
delete Database.query(orphanedLogsQuery);
}
RollupLogger.Instance.save();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public without sharing class RollupLogEventHandler {

for (RollupLogEvent__e logEvent : logEvents) {
RollupLog__c rollupLog = new RollupLog__c(
ErrorWouldHaveBeenThrown__c = logEvent.LoggingLevel__c == LoggingLevel.ERROR.name(),
ErrorWouldHaveBeenThrown__c = logEvent.LoggingLevel__c == System.LoggingLevel.ERROR.name(),
LoggedBy__c = Id.valueOf(logEvent.LoggedBy__c),
TransactionId__c = logEvent.TransactionId__c
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<?xml version="1.0" encoding="UTF-8" ?>
<CustomMetadata
xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<label>Custom Logging Debug Level</label>
<protected>false</protected>
<values>
<field>Description__c</field>
<value xsi:type="xsd:string">Conforms to the standard LoggingLevel enum - valid values are ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST. FINEST provides the highest level of detail; ERROR provides the least.</value>
<value
xsi:type="xsd:string"
>Conforms to the standard System.LoggingLevel enum - valid values are ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST. FINEST provides the highest level of detail; ERROR provides the least.</value>
</values>
<values>
<field>RollupPlugin__c</field>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>ErrorWouldHaveBeenThrown__c</fullName>
<defaultValue>false</defaultValue>
<description>If Rollup logs an otherwise fatal exception (with LoggingLevel.ERROR), this field is checked off</description>
<description>If Rollup logs an otherwise fatal exception (with System.LoggingLevel.ERROR), this field is checked off</description>
<externalId>false</externalId>
<inlineHelpText>If Rollup logs an otherwise fatal exception (with LoggingLevel.ERROR), this field is checked off</inlineHelpText>
<inlineHelpText>If Rollup logs an otherwise fatal exception (with System.LoggingLevel.ERROR), this field is checked off</inlineHelpText>
<label>Error Would Have Been Thrown</label>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ private class RollupCustomObjectLoggerTests {
static void shouldSaveToRollupLog() {
Rollup.defaultControl = new RollupControl__mdt(IsRollupLoggingEnabled__c = true);
RollupCustomObjectLogger rollupCustomLogger = new RollupCustomObjectLogger();
rollupCustomLogger.log('Test log', LoggingLevel.DEBUG);
rollupCustomLogger.log('Test log', System.LoggingLevel.DEBUG);
rollupCustomLogger.log('Second test log with record', new Account(), LoggingLevel.ERROR);

Test.startTest();
Expand All @@ -22,10 +22,10 @@ private class RollupCustomObjectLoggerTests {

// Rollup Log Entries
System.assertEquals(2, firstEntry.RollupLogEntry__r.size());
System.assertEquals(LoggingLevel.DEBUG.name(), firstEntry.RollupLogEntry__r[0].LoggingLevel__c);
System.assertEquals(System.LoggingLevel.DEBUG.name(), firstEntry.RollupLogEntry__r[0].LoggingLevel__c);
System.assertEquals('Rollup ' + RollupLogger.CURRENT_VERSION_NUMBER + ': Test log', firstEntry.RollupLogEntry__r[0].Message__c);

System.assertEquals(LoggingLevel.ERROR.name(), firstEntry.RollupLogEntry__r[1].LoggingLevel__c);
System.assertEquals(System.LoggingLevel.ERROR.name(), firstEntry.RollupLogEntry__r[1].LoggingLevel__c);
System.assertEquals(true, firstEntry.RollupLogEntry__r[1].Message__c.contains('Second test log with record' + '\n' + JSON.serializePretty(new Account())));
}

Expand All @@ -36,7 +36,7 @@ private class RollupCustomObjectLoggerTests {
// this test is to ensure a RollupLogEntry__c is created
RollupCustomObjectLogger rollupCustomLogger = new RollupCustomObjectLogger();
Integer maximumLength = RollupLogEvent__e.Message__c.getDescribe().getLength();
rollupCustomLogger.log('1'.repeat(maximumLength + 1), LoggingLevel.ERROR);
rollupCustomLogger.log('1'.repeat(maximumLength + 1), System.LoggingLevel.ERROR);

Test.startTest();
rollupCustomLogger.save();
Expand All @@ -51,10 +51,10 @@ private class RollupCustomObjectLoggerTests {
static void shouldNotLogBelowSpecifiedLoggingLevel() {
Rollup.defaultControl = new RollupControl__mdt(IsRollupLoggingEnabled__c = true);
// override whatever's included in the CMDT to ensure we arrive at this value deterministically
RollupPlugin.parameterMock = new RollupPluginParameter__mdt(Value__c = LoggingLevel.DEBUG.name());
RollupPlugin.parameterMock = new RollupPluginParameter__mdt(Value__c = System.LoggingLevel.DEBUG.name());

RollupCustomObjectLogger rollupCustomLogger = new RollupCustomObjectLogger();
rollupCustomLogger.log('Test message', LoggingLevel.FINE);
rollupCustomLogger.log('Test message', System.LoggingLevel.FINE);

Test.startTest();
rollupCustomLogger.save();
Expand All @@ -68,7 +68,7 @@ private class RollupCustomObjectLoggerTests {
Rollup.defaultControl = new RollupControl__mdt(IsRollupLoggingEnabled__c = true);
RollupPlugin.pluginMocks.add(new RollupPlugin__mdt(DeveloperName = RollupCustomObjectLogger.class.getName()));
// load a valid message into the buffer prior to disabling logging again
RollupLogger.Instance.log('Test message', LoggingLevel.ERROR);
RollupLogger.Instance.log('Test message', System.LoggingLevel.ERROR);
RollupLogger.Instance.updateRollupControl(new RollupControl__mdt(IsRollupLoggingEnabled__c = false));

Test.startTest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ private class RollupLogBatchPurgerTests {
List<RollupLog__c> logs = new List<RollupLog__c>{ log, logWithoutChildren };
insert logs;

RollupLogEntry__c entry = new RollupLogEntry__c(LoggingLevel__c = 'DEBUG', RollupLog__c = log.Id);
RollupLogEntry__c entry = new RollupLogEntry__c(LoggingLevel__c = System.LoggingLevel.DEBUG.name(), RollupLog__c = log.Id);
insert entry;
// UTC time can lead to some weird Datetime issues with adding simply a single day
// Let's go with 2 to make things completely solid
Expand Down
2 changes: 1 addition & 1 deletion plugins/NebulaLogger/classes/RollupNebulaLoggerAdapter.cls
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class RollupNebulaLoggerAdapter extends RollupLogger {
Logger.saveLog();
}

protected override void innerLog(String logString, Object logObject, LoggingLevel logLevel) {
protected override void innerLog(String logString, Object logObject, System.LoggingLevel logLevel) {
logString = logString + '\n' + this.getLogStringFromObject(logObject);
Logger.newEntry(logLevel, this.getBaseLoggingMessage() + logString);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ private class RollupNebulaLoggerAdapterTest {
String testString = 'Test String';

Test.startTest();
RollupLogger.Instance.log(testString, new Account(), LoggingLevel.INFO);
RollupLogger.Instance.log(testString, new Account(), System.LoggingLevel.INFO);
RollupLogger.Instance.save();
Test.stopTest();

Expand Down
4 changes: 2 additions & 2 deletions rollup-namespaced/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ For more info, see the base `README`.

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaYwAAK">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaZBAA0">
<img alt="Deploy to Salesforce"
src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaYwAAK">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OaZBAA0">
<img alt="Deploy to Salesforce Sandbox"
src="./media/deploy-package-to-sandbox.png">
</a>
3 changes: 2 additions & 1 deletion rollup-namespaced/sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"apex-rollup-namespaced@1.1.10": "04t6g000008OaOBAA0",
"apex-rollup-namespaced@1.1.11": "04t6g000008OaOzAAK",
"apex-rollup-namespaced@1.1.12": "04t6g000008OaUZAA0",
"apex-rollup-namespaced@1.1.13": "04t6g000008OaYwAAK"
"apex-rollup-namespaced@1.1.13": "04t6g000008OaYwAAK",
"apex-rollup-namespaced@1.1.14": "04t6g000008OaZBAA0"
}
}
Loading

0 comments on commit 403fa58

Please sign in to comment.