From 692d8d26e20a7f7381c04004f8dedb6c1eac60dd Mon Sep 17 00:00:00 2001 From: jmercie Date: Thu, 28 May 2026 13:54:50 -0300 Subject: [PATCH 1/2] fix: skip System.debug() in LogEntryEventBuilder when running in managed package Managed package subscribers cannot see namespaced debug logs, so skip the per-entry Apex debug path to avoid unnecessary overhead (issue #889). Co-authored-by: Cursor --- .../classes/LogEntryEventBuilder.cls | 16 +++++++- .../classes/LogEntryEventBuilder_Tests.cls | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls b/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls index ef5a8f332..22a03ac68 100644 --- a/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls +++ b/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls @@ -32,6 +32,9 @@ global with sharing class LogEntryEventBuilder { @TestVisible private String debugMessage = ''; + + @TestVisible + private static Boolean isApexSystemDebugSupportedOverride; private Boolean detailsAreSet = false; private Boolean shouldSave; private Set tags = new Set(); @@ -775,7 +778,9 @@ global with sharing class LogEntryEventBuilder { this.logEntryEvent.put(field, value); } catch (System.Exception ex) { LogMessage logMessage = new LogMessage('Could not set field {0} with value {1}', field, value); - System.debug(System.LoggingLevel.WARN, logMessage.getMessage()); + if (isApexSystemDebugSupported()) { + System.debug(System.LoggingLevel.WARN, logMessage.getMessage()); + } } } @@ -922,7 +927,7 @@ global with sharing class LogEntryEventBuilder { @SuppressWarnings('PMD.AvoidDebugStatements') private void logToApexDebug(String message) { - if (this.userSettings.IsApexSystemDebugLoggingEnabled__c == false) { + if (this.userSettings.IsApexSystemDebugLoggingEnabled__c == false || isApexSystemDebugSupported() == false) { return; } @@ -1139,6 +1144,13 @@ global with sharing class LogEntryEventBuilder { } // Private static helper methods + private static Boolean isApexSystemDebugSupported() { + if (System.Test.isRunningTest() && isApexSystemDebugSupportedOverride != null) { + return isApexSystemDebugSupportedOverride; + } + return String.isBlank(NAMESPACE_PREFIX); + } + @TestVisible private static void setMockDataMaskRule(LogEntryDataMaskRule__mdt dataMaskRule) { CACHED_DATA_MASK_RULES.put(dataMaskRule.DeveloperName, dataMaskRule); diff --git a/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls index 1c9ad3387..2e585b096 100644 --- a/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls @@ -2496,6 +2496,44 @@ private class LogEntryEventBuilder_Tests { System.Assert.isNull(builder.getLogEntryEvent().get(datetimeField)); } + @IsTest + static void it_should_skip_apex_system_debug_when_not_supported() { + LogEntryEventBuilder.isApexSystemDebugSupportedOverride = false; + try { + DebugStringExample example = new DebugStringExample(); + LoggerSettings__c userSettings = getUserSettings(); + userSettings.IsApexSystemDebugLoggingEnabled__c = true; + LogEntryEventBuilder builder = example.myMethod(userSettings); + + System.Assert.areEqual('', builder.debugMessage); + System.Assert.areEqual(example.loggingString, builder.getLogEntryEvent().Message__c); + } finally { + LogEntryEventBuilder.isApexSystemDebugSupportedOverride = null; + } + } + + @IsTest + static void it_should_use_apex_system_debug_when_supported() { + LogEntryEventBuilder.isApexSystemDebugSupportedOverride = true; + try { + LoggerParameter.setMock( + new LoggerParameter__mdt(DeveloperName = 'SystemDebugMessageFormat', Value__c = '{OriginLocation__c}\n{Message__c}: {LoggingLevel__c}') + ); + + DebugStringExample example = new DebugStringExample(); + LoggerSettings__c userSettings = getUserSettings(); + userSettings.IsApexSystemDebugLoggingEnabled__c = true; + LogEntryEventBuilder builder = example.myMethod(userSettings); + + System.Assert.areEqual( + DebugStringExample.class.getName() + '.myMethod' + '\n' + example.loggingString + ': ' + System.LoggingLevel.DEBUG.name(), + builder.debugMessage + ); + } finally { + LogEntryEventBuilder.isApexSystemDebugSupportedOverride = null; + } + } + @IsTest static void it_should_use_configured_log_entry_event_fields_for_debug_string() { // Don't bother testing stack trace logic when using a namespace prefix - there are From 3cdcda6b35a7d355051e4412934de0e05d8ec1c7 Mon Sep 17 00:00:00 2001 From: jmercie Date: Thu, 28 May 2026 15:05:57 -0300 Subject: [PATCH 2/2] refactor: Add comments, re-organize the code for readability and adjust test assertion to add messages. --- .../classes/LogEntryEventBuilder.cls | 23 ++++---- .../classes/LogEntryEventBuilder_Tests.cls | 54 +++++++++---------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls b/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls index 22a03ac68..3a963f3f0 100644 --- a/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls +++ b/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls @@ -34,7 +34,8 @@ global with sharing class LogEntryEventBuilder { private String debugMessage = ''; @TestVisible - private static Boolean isApexSystemDebugSupportedOverride; + private static Boolean isApexSystemDebugSupportedOverride = true; // default to true for backwards compatibility with existing tests + private Boolean detailsAreSet = false; private Boolean shouldSave; private Set tags = new Set(); @@ -777,8 +778,8 @@ global with sharing class LogEntryEventBuilder { try { this.logEntryEvent.put(field, value); } catch (System.Exception ex) { - LogMessage logMessage = new LogMessage('Could not set field {0} with value {1}', field, value); if (isApexSystemDebugSupported()) { + LogMessage logMessage = new LogMessage('Could not set field {0} with value {1}', field, value); System.debug(System.LoggingLevel.WARN, logMessage.getMessage()); } } @@ -1144,13 +1145,6 @@ global with sharing class LogEntryEventBuilder { } // Private static helper methods - private static Boolean isApexSystemDebugSupported() { - if (System.Test.isRunningTest() && isApexSystemDebugSupportedOverride != null) { - return isApexSystemDebugSupportedOverride; - } - return String.isBlank(NAMESPACE_PREFIX); - } - @TestVisible private static void setMockDataMaskRule(LogEntryDataMaskRule__mdt dataMaskRule) { CACHED_DATA_MASK_RULES.put(dataMaskRule.DeveloperName, dataMaskRule); @@ -1352,6 +1346,17 @@ global with sharing class LogEntryEventBuilder { return securityDecision.getRecords(); } + /** + * @description Returns whether Apex System.debug() is supported, supports an override for testing purposes. + * @return `Boolean` true if Apex System.debug() is supported, false otherwise + */ + private static Boolean isApexSystemDebugSupported() { + if (System.Test.isRunningTest()) { + return isApexSystemDebugSupportedOverride; + } + return String.isBlank(NAMESPACE_PREFIX); + } + @SuppressWarnings('PMD.ApexDoc') public class LoggingContext { public String currentEntryScenario; diff --git a/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls index 2e585b096..8b234c9b3 100644 --- a/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls @@ -2498,40 +2498,40 @@ private class LogEntryEventBuilder_Tests { @IsTest static void it_should_skip_apex_system_debug_when_not_supported() { + Test.startTest(); LogEntryEventBuilder.isApexSystemDebugSupportedOverride = false; - try { - DebugStringExample example = new DebugStringExample(); - LoggerSettings__c userSettings = getUserSettings(); - userSettings.IsApexSystemDebugLoggingEnabled__c = true; - LogEntryEventBuilder builder = example.myMethod(userSettings); + DebugStringExample example = new DebugStringExample(); + LoggerSettings__c userSettings = getUserSettings(); + userSettings.IsApexSystemDebugLoggingEnabled__c = true; + LogEntryEventBuilder builder = example.myMethod(userSettings); + Test.stopTest(); - System.Assert.areEqual('', builder.debugMessage); - System.Assert.areEqual(example.loggingString, builder.getLogEntryEvent().Message__c); - } finally { - LogEntryEventBuilder.isApexSystemDebugSupportedOverride = null; - } + System.Assert.areEqual( + '', + builder.debugMessage, + 'Debug message should be empty when Apex System.debug() is not supported, ie: executed in Managed Package context' + ); + System.Assert.areEqual(example.loggingString, builder.getLogEntryEvent().Message__c, 'Message should be set on the log entry event'); } @IsTest static void it_should_use_apex_system_debug_when_supported() { - LogEntryEventBuilder.isApexSystemDebugSupportedOverride = true; - try { - LoggerParameter.setMock( - new LoggerParameter__mdt(DeveloperName = 'SystemDebugMessageFormat', Value__c = '{OriginLocation__c}\n{Message__c}: {LoggingLevel__c}') - ); + Test.startTest(); + LoggerParameter.setMock( + new LoggerParameter__mdt(DeveloperName = 'SystemDebugMessageFormat', Value__c = '{OriginLocation__c}\n{Message__c}: {LoggingLevel__c}') + ); - DebugStringExample example = new DebugStringExample(); - LoggerSettings__c userSettings = getUserSettings(); - userSettings.IsApexSystemDebugLoggingEnabled__c = true; - LogEntryEventBuilder builder = example.myMethod(userSettings); - - System.Assert.areEqual( - DebugStringExample.class.getName() + '.myMethod' + '\n' + example.loggingString + ': ' + System.LoggingLevel.DEBUG.name(), - builder.debugMessage - ); - } finally { - LogEntryEventBuilder.isApexSystemDebugSupportedOverride = null; - } + DebugStringExample example = new DebugStringExample(); + LoggerSettings__c userSettings = getUserSettings(); + userSettings.IsApexSystemDebugLoggingEnabled__c = true; + LogEntryEventBuilder builder = example.myMethod(userSettings); + Test.stopTest(); + + System.Assert.areEqual( + DebugStringExample.class.getName() + '.myMethod' + '\n' + example.loggingString + ': ' + System.LoggingLevel.DEBUG.name(), + builder.debugMessage, + 'Debug message should be set when Apex System.debug() is supported, ie: executed in Unmanaged Package context and IsApexSystemDebugLoggingEnabled__c is true' + ); } @IsTest