Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ name: Build

env:
SF_DISABLE_AUTOUPDATE: true
SF_LOG_LEVEL: debug
SF_IMPROVED_CODE_COVERAGE: true
SF_LOG_LEVEL: error
SF_PROJECT_AUTOUPDATE_DISABLE_FOR_PACKAGE_VERSION_CREATE: true
SF_SKIP_NEW_VERSION_CHECK: true

on:
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

The most robust observability solution for Salesforce experts. Built 100% natively on the platform, and designed to work seamlessly with Apex, Lightning Components, Flow, OmniStudio, and integrations.

## Unlocked Package - v4.19.4
## Unlocked Package - v4.19.5

[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IawHAAS)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IawHAAS)
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IzRdAAK)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IzRdAAK)
[![View Documentation](./images/btn-view-documentation.png)](https://github.com/jongpie/NebulaLogger/wiki)

`sf package install --wait 20 --security-type AdminsOnly --package 04tg7000000IawHAAS`
`sf package install --wait 20 --security-type AdminsOnly --package 04tg7000000IzRdAAK`

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ global inherited sharing class FlowCollectionLogEntry {
* @description Optionally rollback Database operations executed until Apex action was called and save the log entry.
*/
@InvocableVariable(required=false label='(Optional) Throw FlowException for Fault Error Message')
global Boolean shouldThrowFaultMessageException = false;
global Boolean shouldThrowFaultMessageException;

/**
* @description Optionally choose to save any pending log entries
*/
@InvocableVariable(required=false label='(Optional) Save Log')
global Boolean saveLog = false;
global Boolean saveLog;

/**
* @description Optionally choose the save method to use when 'Save Log' is true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ global inherited sharing class FlowLogEntry {
* @description Optionally rollback Database operations executed until Apex action was called and save the log entry.
*/
@InvocableVariable(required=false label='(Optional) Throw FlowException for Fault Error Message')
global Boolean shouldThrowFaultMessageException = false;
global Boolean shouldThrowFaultMessageException;

/**
* @description Optionally choose to save any pending log entries
*/
@InvocableVariable(required=false label='(Optional) Save Log')
global Boolean saveLog = false;
global Boolean saveLog;

/**
* @description Optionally choose the save method to use when 'Save Log' is true
Expand Down
10 changes: 5 additions & 5 deletions nebula-logger/core/main/logger-engine/classes/FlowLogger.cls
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public inherited sharing class FlowLogger {
this.logEntryEvent.ExceptionSourceActionName__c = null;

Boolean hasFaultMessage = String.isNotBlank(this.faultMessage);
if (hasFaultMessage || this.shouldThrowFaultMessageException) {
if (hasFaultMessage || this.shouldThrowFaultMessageException == true) {
// For now, this code takes the approach of treating the Flow itself as the source of the exception.
// But, if the exception actually came from Apex (and is surfaced by Flow), it'd be more accurate to list
// the Apex class/trigger/whatever as the exception's "source" fields.
Expand Down Expand Up @@ -173,17 +173,17 @@ public inherited sharing class FlowLogger {
for (LogEntry flowEntry : flowEntries) {
flowEntry.addToLoggerBuffer();

if (flowEntry.saveLog) {
saveLog = flowEntry.saveLog;
if (flowEntry.saveLog == true) {
saveLog = true;
if (String.isNotBlank(flowEntry.saveMethodName)) {
saveMethod = Logger.SaveMethod.valueOf(flowEntry.saveMethodName);
}
}
if (String.isNotBlank(flowEntry.faultMessage)) {
faultMessage = flowEntry.faultMessage;
}
if (flowEntry.shouldThrowFaultMessageException) {
shouldThrowFaultMessageException = flowEntry.shouldThrowFaultMessageException;
if (flowEntry.shouldThrowFaultMessageException == true) {
shouldThrowFaultMessageException = true;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ global inherited sharing class FlowRecordLogEntry {
* @description Optionally rollback Database operations executed until Apex action was called and save the log entry.
*/
@InvocableVariable(required=false label='(Optional) Throw FlowException for Fault Error Message')
global Boolean shouldThrowFaultMessageException = false;
global Boolean shouldThrowFaultMessageException;

/**
* @description Optionally choose to save any pending log entries
*/
@InvocableVariable(required=false label='(Optional) Save Log')
global Boolean saveLog = false;
global Boolean saveLog;

/**
* @description Optionally choose the save method to use when 'Save Log' is true
Expand Down
2 changes: 1 addition & 1 deletion nebula-logger/core/main/logger-engine/classes/Logger.cls
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
global with sharing class Logger {
// There's no reliable way to get the version number dynamically in Apex
@TestVisible
private static final String CURRENT_VERSION_NUMBER = 'v4.19.4';
private static final String CURRENT_VERSION_NUMBER = 'v4.19.5';
private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG;
private static final List<LogEntryEventBuilder> LOG_ENTRIES_BUFFER = new List<LogEntryEventBuilder>();
private static final String MISSING_SCENARIO_ERROR_MESSAGE = 'No logger scenario specified. A scenario is required for logging in this org.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import LoggerServiceTaskQueue from './loggerServiceTaskQueue';
import getSettings from '@salesforce/apex/ComponentLogger.getSettings';
import saveComponentLogEntries from '@salesforce/apex/ComponentLogger.saveComponentLogEntries';

const CURRENT_VERSION_NUMBER = 'v4.19.4';
const CURRENT_VERSION_NUMBER = 'v4.19.5';

const CONSOLE_OUTPUT_CONFIG = {
messagePrefix: `%c Nebula Logger ${CURRENT_VERSION_NUMBER} `,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,28 @@ private class FlowCollectionLogEntry_Tests {
System.Assert.isTrue(tagsSet.contains(publishedTag), publishedTag + ' not found in expected tags set: ' + tagsSet);
}
}

@IsTest
static void it_should_handle_null_boolean_inputs_from_flow() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
Logger.getUserSettings().LoggingLevel__c = System.LoggingLevel.FINEST.name();
LoggerTestConfigurator.setupMockSObjectHandlerConfigurations();
Schema.User currentUser = new Schema.User(Id = System.UserInfo.getUserId(), Username = System.UserInfo.getUsername());
FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry();
flowCollectionEntry.loggingLevelName = System.LoggingLevel.DEBUG.name();
flowCollectionEntry.records = new List<SObject>{ currentUser };
flowCollectionEntry.saveLog = null;
flowCollectionEntry.shouldThrowFaultMessageException = null;

Exception thrownException;
try {
FlowCollectionLogEntry.addFlowCollectionEntries(new List<FlowCollectionLogEntry>{ flowCollectionEntry });
} catch (Exception ex) {
thrownException = ex;
}

System.Assert.isNull(thrownException, 'Null Boolean inputs from Flow should not throw a NullPointerException');
System.Assert.areEqual(1, Logger.getBufferSize(), 'Entry should have been buffered without saving');
System.Assert.areEqual(0, Logger.saveLogCallCount, 'A null saveLog should not trigger an auto-save');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,28 @@ private class FlowLogEntry_Tests {
System.Assert.areEqual(flowEntry.scenario, publishedLogEntryEvent.EntryScenario__c);
}

@IsTest
static void it_should_handle_null_boolean_inputs_from_flow() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
Logger.getUserSettings().LoggingLevel__c = System.LoggingLevel.FINEST.name();
LoggerTestConfigurator.setupMockSObjectHandlerConfigurations();
FlowLogEntry flowEntry = createFlowLogEntry();
flowEntry.loggingLevelName = System.LoggingLevel.DEBUG.name();
flowEntry.saveLog = null;
flowEntry.shouldThrowFaultMessageException = null;

Exception thrownException;
try {
FlowLogEntry.addFlowEntries(new List<FlowLogEntry>{ flowEntry });
} catch (Exception ex) {
thrownException = ex;
}

System.Assert.isNull(thrownException, 'Null Boolean inputs from Flow should not throw a NullPointerException');
System.Assert.areEqual(1, Logger.getBufferSize(), 'Entry should have been buffered without saving');
System.Assert.areEqual(0, Logger.saveLogCallCount, 'A null saveLog should not trigger an auto-save');
}

@IsTest
static void it_should_add_tags_to_log_entry() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,54 @@ private class FlowLogger_Tests {
System.Assert.areEqual(flowEntry.timestamp, publishedLogEntryEvent.Timestamp__c);
}

@IsTest
static void it_should_treat_null_saveLog_as_false() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
System.LoggingLevel entryLoggingLevel = System.LoggingLevel.DEBUG;
Logger.getUserSettings().LoggingLevel__c = entryLoggingLevel.name();
LoggerTestConfigurator.setupMockSObjectHandlerConfigurations();
FlowLogger.LogEntry flowEntry = new FlowLogger.LogEntry();
flowEntry.flowName = 'MyFlow';
flowEntry.message = 'hello from Flow';
flowEntry.loggingLevelName = entryLoggingLevel.name();
flowEntry.saveLog = null;
flowEntry.shouldThrowFaultMessageException = null;
flowEntry.timestamp = System.now();

FlowLogger.addEntries(new List<FlowLogger.LogEntry>{ flowEntry });

System.Assert.areEqual(1, Logger.getBufferSize(), 'Entry should have been buffered without saving');
System.Assert.areEqual(0, Logger.saveLogCallCount, 'A null saveLog should not trigger an auto-save');
System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishCallCount());
}

@IsTest
static void it_should_treat_null_shouldThrowFaultMessageException_as_false_when_faultMessage_is_provided() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
System.LoggingLevel entryLoggingLevel = System.LoggingLevel.ERROR;
Logger.getUserSettings().LoggingLevel__c = entryLoggingLevel.name();
LoggerTestConfigurator.setupMockSObjectHandlerConfigurations();
FlowLogger.LogEntry flowEntry = new FlowLogger.LogEntry();
flowEntry.flowName = 'MyFlow';
flowEntry.message = 'hello from Flow';
flowEntry.loggingLevelName = entryLoggingLevel.name();
flowEntry.saveLog = null;
flowEntry.faultMessage = 'Something went wrong';
flowEntry.shouldThrowFaultMessageException = null;
flowEntry.timestamp = System.now();

Exception thrownException;
try {
FlowLogger.addEntries(new List<FlowLogger.LogEntry>{ flowEntry });
} catch (Exception ex) {
thrownException = ex;
}

System.Assert.isNull(thrownException, 'A null shouldThrowFaultMessageException should not throw');
System.Assert.areEqual(1, Logger.getBufferSize(), 'Entry should still be buffered with a fault message');
System.Assert.areEqual(0, Logger.saveLogCallCount, 'A null saveLog should not trigger an auto-save');
}

@IsTest
static void it_truncates_too_long_exception_messages() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,4 +332,28 @@ private class FlowRecordLogEntry_Tests {
System.Assert.isTrue(tagsSet.contains(publishedTag), publishedTag + ' not found in expected tags set: ' + tagsSet);
}
}

@IsTest
static void it_should_handle_null_boolean_inputs_from_flow() {
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
Logger.getUserSettings().LoggingLevel__c = System.LoggingLevel.FINEST.name();
LoggerTestConfigurator.setupMockSObjectHandlerConfigurations();
Schema.User currentUser = new Schema.User(Id = System.UserInfo.getUserId(), Username = System.UserInfo.getUsername());
FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry();
flowRecordEntry.loggingLevelName = System.LoggingLevel.DEBUG.name();
flowRecordEntry.record = currentUser;
flowRecordEntry.saveLog = null;
flowRecordEntry.shouldThrowFaultMessageException = null;

Exception thrownException;
try {
FlowRecordLogEntry.addFlowRecordEntries(new List<FlowRecordLogEntry>{ flowRecordEntry });
} catch (Exception ex) {
thrownException = ex;
}

System.Assert.isNull(thrownException, 'Null Boolean inputs from Flow should not throw a NullPointerException');
System.Assert.areEqual(1, Logger.getBufferSize(), 'Entry should have been buffered without saving');
System.Assert.areEqual(0, Logger.saveLogCallCount, 'A null saveLog should not trigger an auto-save');
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nebula-logger",
"version": "4.19.4",
"version": "4.19.5",
"description": "The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.",
"author": "Jonathan Gillespie",
"license": "MIT",
Expand Down
7 changes: 4 additions & 3 deletions sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"path": "./nebula-logger/core",
"definitionFile": "./config/scratch-orgs/base-scratch-def.json",
"scopeProfiles": true,
"versionNumber": "4.19.4.NEXT",
"versionName": "Capture Apex Cursor and Apex Pagination Cursor Transaction Limits",
"versionDescription": "Added new fields on LogEntryEvent__e and LogEntry__c to capture the used and max values for System.Limits.getApexCursors(), System.Limits.getApexPaginationCursors(), and System.Limits.getApexPaginationCursorRows()",
"versionNumber": "4.19.5.NEXT",
"versionName": "Fixed NullPointerException on Flow Logging Actions",
"versionDescription": "Fixed #997 NullPointerException that occurs when Flow passes a null value for the optional Save Log and Throw FlowException for Fault Error Message inputs, which happens now that Salesforce has removed the per-input include toggles from the Flow Builder action panel",
"postInstallUrl": "https://github.com/jongpie/NebulaLogger/wiki",
"releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases",
"unpackagedMetadata": {
Expand Down Expand Up @@ -244,6 +244,7 @@
"Nebula Logger - Core@4.19.2-optimized-data-masking": "04tg7000000HNrRAAW",
"Nebula Logger - Core@4.19.3-fixed-mixed_dml_operation-errors-in-tests": "04tg7000000IEirAAG",
"Nebula Logger - Core@4.19.4-capture-apex-cursor-and-apex-pagination-cursor-transaction-limits": "04tg7000000IawHAAS",
"Nebula Logger - Core@4.19.5-fixed-nullpointerexception-on-flow-logging-actions": "04tg7000000IzRdAAK",
"Nebula Logger - Core Plugin - Async Failure Additions": "0Ho5Y000000blO4SAI",
"Nebula Logger - Core Plugin - Async Failure Additions@1.0.0": "04t5Y0000015lhiQAA",
"Nebula Logger - Core Plugin - Async Failure Additions@1.0.1": "04t5Y0000015lhsQAA",
Expand Down
8 changes: 4 additions & 4 deletions skills/nebula-logger-install/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ Always confirm the latest version on:

- https://github.com/jongpie/NebulaLogger/releases

### Unlocked Package - v4.19.4
### Unlocked Package - v4.19.5

- Sandbox install link: `https://test.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IawHAAS`
- Production install link: `https://login.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IawHAAS`
- Salesforce CLI: `sf package install --wait 20 --security-type AdminsOnly --package 04tg7000000IawHAAS`
- Sandbox install link: `https://test.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IzRdAAK`
- Production install link: `https://login.salesforce.com/packaging/installPackage.apexp?p0=04tg7000000IzRdAAK`
- Salesforce CLI: `sf package install --wait 20 --security-type AdminsOnly --package 04tg7000000IzRdAAK`

### Managed Package - v4.19.0

Expand Down