diff --git a/README.md b/README.md index 1e8c47490..3fe6f2bba 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,15 @@ The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects. -## Unlocked Package - v4.12.6 +## Unlocked Package - v4.12.7 -[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk5UQAS) -[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk5UQAS) +[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk6IQAS) +[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk6IQAS) [![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/) -`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001Mk5UQAS` +`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001Mk6IQAS` -`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001Mk5UQAS` +`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001Mk6IQAS` --- diff --git a/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls b/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls index a4bfce86f..db7d1fddb 100644 --- a/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls +++ b/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls @@ -9,8 +9,19 @@ * @see Logger * @see LogEntryEventBuilder */ -@SuppressWarnings('PMD.ExcessivePublicCount, PMD.StdCyclomaticComplexity') +@SuppressWarnings('PMD.ExcessivePublicCount, PMD.PropertyNamingConventions, PMD.StdCyclomaticComplexity') public inherited sharing class ComponentLogger { + private static final String LOGGER_COMPONENT_NAME { + get { + if (LOGGER_COMPONENT_NAME == null) { + String namespace = String.isNotBlank(Logger.getNamespacePrefix()) ? Logger.getNamespacePrefix() : 'c'; + LOGGER_COMPONENT_NAME = '/' + namespace + '/logger.js'; + } + return LOGGER_COMPONENT_NAME; + } + set; + } + static { Logger.ignoreOrigin(ComponentLogger.class); } @@ -90,14 +101,13 @@ public inherited sharing class ComponentLogger { Boolean isAuraComponent = false; if (String.isNotBlank(stackTraceString)) { - String loggerComponentReferenceToIgnore = '/c/logger.js'; String auraComponentContent = '/n/components/'; - String lwcModuleContent = '/n/modules/'; + String lwcModuleContent = 'modules/'; Boolean parentComponentFound = false; List stackTraceLines = new List(); for (String currentStackTraceLine : stackTraceString.split('\n')) { - if (currentStackTraceLine.contains(loggerComponentReferenceToIgnore)) { + if (currentStackTraceLine.contains(LOGGER_COMPONENT_NAME)) { continue; } else if (parentComponentFound == false && currentStackTraceLine.contains(auraComponentContent)) { isAuraComponent = true; diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls index 817056742..71709b906 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.12.6'; + private static final String CURRENT_VERSION_NUMBER = 'v4.12.7'; private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG; private static final Set IGNORED_APEX_CLASSES = initializeIgnoredApexClasses(); private static final List LOG_ENTRIES_BUFFER = new List(); @@ -109,7 +109,7 @@ global with sharing class Logger { // The rest of the codebase should use a method in Logger.cls System.debug(System.LoggingLevel.INFO, 'Nebula Logger - Version Number: ' + getVersionNumber()); System.debug(System.LoggingLevel.INFO, 'Nebula Logger - Transaction ID: ' + getTransactionId()); - System.debug(System.LoggingLevel.INFO, 'Nebula Logger - Schema.Organization API Version: ' + getOrganizationApiVersion()); + System.debug(System.LoggingLevel.INFO, 'Nebula Logger - Organization API Version: ' + getOrganizationApiVersion()); setScenario(getUserSettings().DefaultScenario__c); } diff --git a/nebula-logger/core/main/logger-engine/lwc/logger/logger.js b/nebula-logger/core/main/logger-engine/lwc/logger/logger.js index a0f48987f..ca78b268c 100644 --- a/nebula-logger/core/main/logger-engine/lwc/logger/logger.js +++ b/nebula-logger/core/main/logger-engine/lwc/logger/logger.js @@ -6,7 +6,7 @@ import { LightningElement, api } from 'lwc'; import { createLoggerService } from './loggerService'; -const CURRENT_VERSION_NUMBER = 'v4.12.6'; +const CURRENT_VERSION_NUMBER = 'v4.12.7'; export default class Logger extends LightningElement { #loggerService = createLoggerService(); diff --git a/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls index b2a7e0450..e8d7e649b 100644 --- a/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls @@ -241,13 +241,49 @@ private class ComponentLogger_Tests { } @IsTest - static void it_should_parse_web_component_stack_trace() { + static void it_should_parse_web_component_stack_trace_when_stack_trace_is_modern_format() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + String expectedComponentType = 'LWC'; + String expectedComponentApiName = 'c/loggerLWCDemo'; + String expectedComponentFunctionName = 'logErrorExample'; + ComponentLogger.ComponentLogEntry componentLogEntry = createMockComponentLogEntry(); + componentLogEntry.stack = getMockModernWebComponentStackTrace(); + System.Assert.areEqual(0, Logger.saveLogCallCount); + System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, null); + + System.Assert.areEqual(1, Logger.saveLogCallCount); + System.Assert.areEqual(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.Assert.areEqual(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.Assert.areEqual('Component', publishedLogEntryEvent.OriginType__c); + System.Assert.areEqual(componentLogEntry.browserFormFactor, publishedLogEntryEvent.BrowserFormFactor__c); + System.Assert.areEqual(componentLogEntry.browserLanguage, publishedLogEntryEvent.BrowserLanguage__c); + System.Assert.areEqual(componentLogEntry.browserScreenResolution, publishedLogEntryEvent.BrowserScreenResolution__c); + System.Assert.areEqual(componentLogEntry.browserUrl, publishedLogEntryEvent.BrowserUrl__c); + System.Assert.areEqual(componentLogEntry.browserUserAgent, publishedLogEntryEvent.BrowserUserAgent__c); + System.Assert.areEqual(componentLogEntry.browserWindowResolution, publishedLogEntryEvent.BrowserWindowResolution__c); + System.Assert.areEqual(componentLogEntry.loggingLevel, publishedLogEntryEvent.LoggingLevel__c); + System.Assert.areEqual(componentLogEntry.message, publishedLogEntryEvent.Message__c); + System.Assert.areEqual('Component', publishedLogEntryEvent.OriginType__c); + System.Assert.areEqual(expectedComponentApiName + '.' + expectedComponentFunctionName, publishedLogEntryEvent.OriginLocation__c); + // TODO Move these asserts to LogEntryHandler_Tests + // System.Assert.areEqual(expectedComponentApiName, publishedLogEntryEvent.ComponentApiName__c); + // System.Assert.areEqual(expectedComponentFunctionName, publishedLogEntryEvent.ComponentFunctionName__c); + System.Assert.areEqual(expectedComponentType, publishedLogEntryEvent.ComponentType__c); + System.Assert.areEqual(componentLogEntry.timestamp, publishedLogEntryEvent.Timestamp__c); + } + + @IsTest + static void it_should_parse_web_component_stack_trace_when_stack_trace_is_legacy_format() { LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); String expectedComponentType = 'LWC'; String expectedComponentApiName = 'c/loggerLWCDemo'; String expectedComponentFunctionName = 'saveLogWebExample'; ComponentLogger.ComponentLogEntry componentLogEntry = createMockComponentLogEntry(); - componentLogEntry.stack = getMockWebComponentStackTrace(); + componentLogEntry.stack = getMockLegacyWebComponentStackTrace(); System.Assert.areEqual(0, Logger.saveLogCallCount); System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); System.Assert.areEqual(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); @@ -422,8 +458,39 @@ private class ComponentLogger_Tests { '\nloggerAuraDemo.js:17:17'; } - private static String getMockWebComponentStackTrace() { - // This is a copy of an actual stack trace generated from c/loggerLWCDemo + private static String getMockModernWebComponentStackTrace() { + // This is a partial copy of an actual stack trace generated from c/loggerLWCDemo in January 2024 + List lwcStackTraceLines = new List{ + '@modules/c/logger.js:33:22', + 'LogEntryBuilder@modules/c/logger.js:59:87', + 'newLogEntry@modules/c/logger.js:189:14', + '_newEntry@modules/c/logger.js:397:44', + 'error@modules/c/logger.js:264:21', + 'logErrorExample@modules/c/loggerLWCDemo.js:266:35', + 'createHooksCallback$LWS/<@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js line 35465 > eval:2583:24', + 'applyOrConstructTrapForTwoOrMoreArgs$LWS@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:32254:38', + 'callHook@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:10035:19', + 'invokeEventListener/<@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:9926:21', + 'runWithBoundaryProtection@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:10517:13', + 'invokeEventListener@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:9921:34', + 'b/<@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:9365:32', + 'handleEvent@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:1615:51', + 'invokeListenersByPlacement/<@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:1660:46', + 'invokeListenersByPlacement@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:1655:21', + 'domListener@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:1670:39', + 'EventListener.handleEvent*attachDOMListener@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:1687:30', + 'addCustomElementEventListener@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:1712:30', + 'patchedAddEventListener@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:3022:50', + 'value@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:5567:53', + 'addEventListener@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:11554:20', + 'applyEventListeners@https://static.lightning.force.com/cs220/auraFW/javascript/YWYyQV90T3g3VDhySzNWUm1kcF9WUVY4bi1LdGdMbklVbHlMdER1eVVlUGcyNDYuMTUuNS0zLjAuNA/aura_proddebug.js:8200:29', + '...blah,blah,blah more javascript code goes here, etc.' + }; + return String.join(lwcStackTraceLines, '\n'); + } + + private static String getMockLegacyWebComponentStackTrace() { + // This is a copy of an actual stack trace generated from c/loggerLWCDemo in August 2021 return 'LogEntryBuilder@https://flow-ability-5496.lightning.force.com/lightning/n/modules/c/logger.js:28:24' + '\nnewLogEntry@https://flow-ability-5496.lightning.force.com/lightning/n/modules/c/logger.js:172:14' + '\n_newEntry@https://flow-ability-5496.lightning.force.com/lightning/n/modules/c/logger.js:349:44' + diff --git a/package.json b/package.json index 71a62648d..07fb64b7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nebula-logger", - "version": "4.12.6", + "version": "4.12.7", "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 92dfa6040..2e5f76ec0 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -13,9 +13,9 @@ "package": "Nebula Logger - Core", "path": "./nebula-logger/core", "definitionFile": "./config/scratch-orgs/base-scratch-def.json", - "versionNumber": "4.12.6.NEXT", - "versionName": "Bugfix to Automatically Truncate LogEntryEvent__e Fields", - "versionDescription": "Updated LoggerDataStore, Logger, and LogEntryEventBuilder to automatically truncate string field values that are too long for the corresponding LogEntryEvent__e fields", + "versionNumber": "4.12.7.NEXT", + "versionName": "Bugfix for LWC Stack Trace Parsing", + "versionDescription": "Fixed ComponentLogger.cls so it handles recent-ish changes to the format of stack traces in LWCs. The field LogEntry__c.OriginLocation__c should now be correctly populated again for LWCs.", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases", "unpackagedMetadata": { "path": "./nebula-logger/extra-tests" @@ -167,6 +167,7 @@ "Nebula Logger - Core@4.12.4-bugfix-child-log__c-records-not-properly-linked-to-parent-log__c-records": "04t5Y000001Mk5KQAS", "Nebula Logger - Core@4.12.5-bugfix-for-name-shadowing-issues-with-schema-namespace": "04t5Y000001Mk5PQAS", "Nebula Logger - Core@4.12.6-bugfix-to-automatically-truncate-logentryevent__e-fields": "04t5Y000001Mk5UQAS", + "Nebula Logger - Core@4.12.7-bugfix-for-lwc-stack-trace-parsing": "04t5Y000001Mk6IQAS", "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",