From ab92cd58b2ba23b982c0d496482dd3ae3756441b Mon Sep 17 00:00:00 2001 From: Jonathan Gillespie Date: Wed, 25 Sep 2024 01:25:15 +0000 Subject: [PATCH] Bugfix: Updated Logger.setAsyncContext() behavior (#770) * 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 --- .github/workflows/build.yml | 8 +- README.md | 10 +- .../main/logger-engine/classes/Logger.cls | 27 +++- .../lwc/logger/logEntryBuilder.js | 2 +- .../logger-engine/classes/Logger_Tests.cls | 132 ++++++++++++++++++ package.json | 2 +- sfdx-project.json | 7 +- 7 files changed, 169 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8ab8326b3..599f609ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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: @@ -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 @@ -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' diff --git a/README.md b/README.md index 06897fbec..bdec5563f 100644 --- a/README.md +++ b/README.md @@ -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` --- diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls index 9fa54941a..f73418b4c 100644 --- a/nebula-logger/core/main/logger-engine/classes/Logger.cls +++ b/nebula-logger/core/main/logger-engine/classes/Logger.cls @@ -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 LOG_ENTRIES_BUFFER = new List(); private static final String MISSING_SCENARIO_ERROR_MESSAGE = 'No logger scenario specified. A scenario is required for logging in this org.'; @@ -196,7 +196,9 @@ 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)); + } } /** @@ -204,7 +206,9 @@ global with sharing class Logger { * @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)); + } } /** @@ -212,7 +216,9 @@ global with sharing class Logger { * @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)); + } } /** @@ -220,7 +226,9 @@ global with sharing class Logger { * @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)); + } } /** @@ -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) { diff --git a/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js b/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js index 1150bda94..2a964b65b 100644 --- a/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js +++ b/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js @@ -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: '⛔', diff --git a/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls index 798db7562..5ea0c6a26 100644 --- a/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls @@ -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); @@ -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); @@ -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); @@ -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'; diff --git a/package.json b/package.json index 4aaf72cdf..d28f0159d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/sfdx-project.json b/sfdx-project.json index 0169bbefc..ce4e0a881 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -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" @@ -195,6 +195,7 @@ "Nebula Logger - Core@4.14.8-store-httprequest-header-keys-&-values": "04t5Y0000015oS1QAI", "Nebula Logger - Core@4.14.9-bugfix:-apex-code-snippets-auto-truncated": "04t5Y0000015oSQQAY", "Nebula Logger - Core@4.14.10-new-callablelogger-apex-class": "04t5Y0000015oTdQAI", + "Nebula Logger - Core@4.14.11-updated-behavior-of-logger.setasynccontext()": "04t5Y0000015oUgQAI", "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",