Skip to content

Commit

Permalink
Bugfix: Updated Logger.setAsyncContext() behavior (#770)
Browse files Browse the repository at this point in the history
* Updated the behavior of Logger.setAsyncContext() to only set the context the first time a non-null context value is provided

* Made some optimizations in build.yml so some steps don't run on draft PRs
  • Loading branch information
jongpie authored Sep 25, 2024
1 parent 1629291 commit ab92cd5
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 19 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ env:

on:
push:
branches:
- main
paths:
- .github/workflows/**
- config/scratch-orgs/**
- nebula-logger/**
- sfdx-project.json
pull_request:
types: [opened, synchronize, reopened]
paths:
- .github/workflows/**
- config/scratch-orgs/**
- nebula-logger/**
- sfdx-project.json

jobs:
code-quality-tests:
Expand Down Expand Up @@ -50,7 +54,7 @@ jobs:
- './nebula-logger/core/**'
- name: 'Authorize Dev Hub'
if: ${{ (github.event_name == 'pull_request') && (steps.changes.outputs.core == 'true') }}
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.draft == false) && (steps.changes.outputs.core == 'true') }}
shell: bash
run: |
npx sf version
Expand All @@ -63,7 +67,7 @@ jobs:
DEV_HUB_JWT_SERVER_KEY: ${{ secrets.DEV_HUB_JWT_SERVER_KEY }}

- name: 'Verify package version number is updated'
if: ${{ (github.event_name == 'pull_request') && (steps.changes.outputs.core == 'true') }}
if: ${{ (github.event_name == 'pull_request') && (github.event.pull_request.draft == false) && (steps.changes.outputs.core == 'true') }}
run: npm run package:version:number:verify

- name: 'Verify LWC with ESLint'
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

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

## Unlocked Package - v4.14.10
## Unlocked Package - v4.14.11

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

`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oTdQAI`
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oUgQAI`

`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oTdQAI`
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oUgQAI`

---

Expand Down
27 changes: 20 additions & 7 deletions 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.14.10';
private static final String CURRENT_VERSION_NUMBER = 'v4.14.11';
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 Expand Up @@ -196,31 +196,39 @@ global with sharing class Logger {
* @param batchableContext - The instance of `Database.BatchableContext` to track
*/
global static void setAsyncContext(Database.BatchableContext batchableContext) {
setAsyncContext(new AsyncContext(batchableContext));
if (batchableContext != null) {
setAsyncContext(new AsyncContext(batchableContext));
}
}

/**
* @description Stores additional details about the current transacation's async context
* @param finalizerContext - The instance of `System.FinalizerContext` to track
*/
global static void setAsyncContext(System.FinalizerContext finalizerContext) {
setAsyncContext(new AsyncContext(finalizerContext));
if (finalizerContext != null) {
setAsyncContext(new AsyncContext(finalizerContext));
}
}

/**
* @description Stores additional details about the current transacation's async context
* @param queueableContext - The instance of `System.QueueableContext` to track
*/
global static void setAsyncContext(System.QueueableContext queueableContext) {
setAsyncContext(new AsyncContext(queueableContext));
if (queueableContext != null) {
setAsyncContext(new AsyncContext(queueableContext));
}
}

/**
* @description Stores additional details about the current transacation's async context
* @param schedulableContext - The instance of `System.SchedulableContext` to track
*/
global static void setAsyncContext(System.SchedulableContext schedulableContext) {
setAsyncContext(new AsyncContext(schedulableContext));
if (schedulableContext != null) {
setAsyncContext(new AsyncContext(schedulableContext));
}
}

/**
Expand Down Expand Up @@ -3415,8 +3423,13 @@ global with sharing class Logger {
}

private static void setAsyncContext(AsyncContext asyncContext) {
currentAsyncContext = asyncContext;
System.debug(System.LoggingLevel.INFO, 'Nebula Logger - Async Context: ' + System.JSON.serializePretty(asyncContext));
// Only set the async context the first time that a non-null value is provided
// Previous versions of Nebula Logger would always set it, but that wasn't the
// intended behavior
if (currentAsyncContext == null) {
currentAsyncContext = asyncContext;
System.debug(System.LoggingLevel.INFO, 'Nebula Logger - Async Context: ' + System.JSON.serializePretty(asyncContext));
}
}

private static SaveMethod getSaveMethod(String saveMethodName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import FORM_FACTOR from '@salesforce/client/formFactor';
import { log as lightningLog } from 'lightning/logger';
import { LoggerStackTrace } from './loggerStackTrace';

const CURRENT_VERSION_NUMBER = 'v4.14.10';
const CURRENT_VERSION_NUMBER = 'v4.14.11';

const LOGGING_LEVEL_EMOJIS = {
ERROR: '⛔',
Expand Down
132 changes: 132 additions & 0 deletions nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,39 @@ private class Logger_Tests {
System.Assert.areEqual(Database.BatchableContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_use_first_non_null_context_details_for_batchable_context_when_event_published() {
Database.BatchableContext nullMockContext = null;
Database.BatchableContext firstNonNullMockContext = new LoggerMockDataCreator.MockBatchableContext();
Database.BatchableContext secondNonNullMockContext = new LoggerMockDataCreator.MockBatchableContext();
System.Assert.areNotEqual(
firstNonNullMockContext,
secondNonNullMockContext,
'Test has started under the wrong conditions, expected 2 different mock contexts'
);
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
LogEntryEvent__e logEntryEvent = Logger.info('hello, world').getLogEntryEvent();
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.isNull(logEntryEvent.AsyncContextType__c);
System.Assert.areEqual(1, Logger.getBufferSize());
System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());

Logger.setAsyncContext(nullMockContext);
Logger.setAsyncContext(firstNonNullMockContext);
Logger.setAsyncContext(secondNonNullMockContext);
Logger.saveLog(Logger.SaveMethod.EVENT_BUS);

System.Assert.areEqual(0, Logger.getBufferSize());
System.Assert.areEqual(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());
System.Assert.areEqual(logEntryEvent, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0));
System.Assert.areEqual(firstNonNullMockContext.getChildJobId(), logEntryEvent.AsyncContextChildJobId__c);
System.Assert.areEqual(firstNonNullMockContext.getJobId(), logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.areEqual(Database.BatchableContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_set_async_context_details_for_finalizer_context_when_event_published() {
Id mockParentAsyncApexJobId = LoggerMockDataCreator.createId(Schema.AsyncApexJob.SObjectType);
Expand All @@ -818,6 +851,39 @@ private class Logger_Tests {
System.Assert.areEqual(System.FinalizerContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_use_first_non_null_context_details_for_finalizer_context_when_event_published() {
System.FinalizerContext nullMockContext = null;
System.FinalizerContext firstNonNullMockContext = new LoggerMockDataCreator.MockFinalizerContext();
System.FinalizerContext secondNonNullMockContext = new LoggerMockDataCreator.MockFinalizerContext();
System.Assert.areNotEqual(
firstNonNullMockContext,
secondNonNullMockContext,
'Test has started under the wrong conditions, expected 2 different mock contexts'
);
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
LogEntryEvent__e logEntryEvent = Logger.info('hello, world').getLogEntryEvent();
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.isNull(logEntryEvent.AsyncContextType__c);
System.Assert.areEqual(1, Logger.getBufferSize());
System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());

Logger.setAsyncContext(nullMockContext);
Logger.setAsyncContext(firstNonNullMockContext);
Logger.setAsyncContext(secondNonNullMockContext);
Logger.saveLog(Logger.SaveMethod.EVENT_BUS);

System.Assert.areEqual(0, Logger.getBufferSize());
System.Assert.areEqual(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());
System.Assert.areEqual(logEntryEvent, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0));
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.areEqual(firstNonNullMockContext.getAsyncApexJobId(), logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.areEqual(System.FinalizerContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_set_async_context_details_for_queueable_context_when_event_published() {
Id mockParentAsyncApexJobId = LoggerMockDataCreator.createId(Schema.AsyncApexJob.SObjectType);
Expand All @@ -844,6 +910,39 @@ private class Logger_Tests {
System.Assert.areEqual(System.QueueableContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_use_first_non_null_context_details_for_queueable_context_when_event_published() {
System.QueueableContext nullMockContext = null;
System.QueueableContext firstNonNullMockContext = new LoggerMockDataCreator.MockQueueableContext();
System.QueueableContext secondNonNullMockContext = new LoggerMockDataCreator.MockQueueableContext();
System.Assert.areNotEqual(
firstNonNullMockContext,
secondNonNullMockContext,
'Test has started under the wrong conditions, expected 2 different mock contexts'
);
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
LogEntryEvent__e logEntryEvent = Logger.info('hello, world').getLogEntryEvent();
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.isNull(logEntryEvent.AsyncContextType__c);
System.Assert.areEqual(1, Logger.getBufferSize());
System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());

Logger.setAsyncContext(nullMockContext);
Logger.setAsyncContext(firstNonNullMockContext);
Logger.setAsyncContext(secondNonNullMockContext);
Logger.saveLog(Logger.SaveMethod.EVENT_BUS);

System.Assert.areEqual(0, Logger.getBufferSize());
System.Assert.areEqual(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());
System.Assert.areEqual(logEntryEvent, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0));
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.areEqual(firstNonNullMockContext.getJobId(), logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.areEqual(System.QueueableContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_set_async_context_details_for_schedulable_context_when_event_published() {
Id mockCronTriggerId = LoggerMockDataCreator.createId(Schema.CronTrigger.SObjectType);
Expand All @@ -869,6 +968,39 @@ private class Logger_Tests {
System.Assert.areEqual(System.SchedulableContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_use_first_non_null_context_details_for_schedulable_context_when_event_published() {
System.SchedulableContext nullMockContext = null;
System.SchedulableContext firstNonNullMockContext = new LoggerMockDataCreator.MockSchedulableContext();
System.SchedulableContext secondNonNullMockContext = new LoggerMockDataCreator.MockSchedulableContext();
System.Assert.areNotEqual(
firstNonNullMockContext,
secondNonNullMockContext,
'Test has started under the wrong conditions, expected 2 different mock contexts'
);
LoggerDataStore.setMock(LoggerMockDataStore.getEventBus());
LogEntryEvent__e logEntryEvent = Logger.info('hello, world').getLogEntryEvent();
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextParentJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextTriggerId__c);
System.Assert.isNull(logEntryEvent.AsyncContextType__c);
System.Assert.areEqual(1, Logger.getBufferSize());
System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());

Logger.setAsyncContext(nullMockContext);
Logger.setAsyncContext(firstNonNullMockContext);
Logger.setAsyncContext(secondNonNullMockContext);
Logger.saveLog(Logger.SaveMethod.EVENT_BUS);

System.Assert.areEqual(0, Logger.getBufferSize());
System.Assert.areEqual(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size());
System.Assert.areEqual(logEntryEvent, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0));
System.Assert.isNull(logEntryEvent.AsyncContextChildJobId__c);
System.Assert.isNull(logEntryEvent.AsyncContextParentJobId__c);
System.Assert.areEqual(firstNonNullMockContext.getTriggerId(), logEntryEvent.AsyncContextTriggerId__c);
System.Assert.areEqual(System.SchedulableContext.class.getName(), logEntryEvent.AsyncContextType__c);
}

@IsTest
static void it_should_set_parent_transaction_id() {
String expectedParentTransactionId = 'imagineThisWereAGuid';
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": "nebula-logger",
"version": "4.14.10",
"version": "4.14.11",
"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.14.10.NEXT",
"versionName": "New CallableLogger Apex class",
"versionDescription": "Added a new CallableLogger class that provides support for both OmniStudio logging, as well as the ability to dynamically call Nebula Logger in Apex when it's available",
"versionNumber": "4.14.11.NEXT",
"versionName": "Updated Behavior of Logger.setAsyncContext()",
"versionDescription": "Updated the behavior of Logger.setAsyncContext() to only set the context the first time a non-null context value is provided. Previously, subsequent calls would overwrite the context value, which wasn't really the intended behaviour.",
"releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases",
"unpackagedMetadata": {
"path": "./nebula-logger/extra-tests"
Expand Down Expand Up @@ -195,6 +195,7 @@
"Nebula Logger - [email protected]&-values": "04t5Y0000015oS1QAI",
"Nebula Logger - [email protected]:-apex-code-snippets-auto-truncated": "04t5Y0000015oSQQAY",
"Nebula Logger - [email protected]": "04t5Y0000015oTdQAI",
"Nebula Logger - [email protected]()": "04t5Y0000015oUgQAI",
"Nebula Logger - Core Plugin - Async Failure Additions": "0Ho5Y000000blO4SAI",
"Nebula Logger - Core Plugin - Async Failure [email protected]": "04t5Y0000015lhiQAA",
"Nebula Logger - Core Plugin - Async Failure [email protected]": "04t5Y0000015lhsQAA",
Expand Down

0 comments on commit ab92cd5

Please sign in to comment.