diff --git a/README.md b/README.md index 4f57789b8..35cd25c10 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.11.6 +## Unlocked Package - v4.11.7 -[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001HZfGQAW) -[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001HZfGQAW) +[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001HZfaQAG) +[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001HZfaQAG) [![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/) -`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001HZfGQAW` +`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001HZfaQAG` -`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001HZfGQAW` +`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001HZfaQAG` --- diff --git a/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls b/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls index 138b7e8db..1ac53c1d0 100644 --- a/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls +++ b/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls @@ -33,7 +33,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { @TestVisible private List logEntryEvents; private List logEntries = new List(); - private Map> logEntryEventUuidToTagNames = new Map>(); + private Map> logEntryEventCompositeKeyToTagNames = new Map>(); private Set tagNames = new Set(); /** @@ -243,8 +243,6 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { } private void upsertLogEntries() { - List logEntriesWithUuid = new List(); - List logEntriesWithoutUuid = new List(); for (LogEntryEvent__e logEntryEvent : this.logEntryEvents) { // Salesforce does not provide precise datetimes in Apex triggers for platform events // Use the string value of timestamp to set the actual datetime field as a workaround @@ -335,7 +333,8 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { TransactionEntryNumber__c = logEntryEvent.TransactionEntryNumber__c, TriggerIsExecuting__c = logEntryEvent.TriggerIsExecuting__c, TriggerOperationType__c = logEntryEvent.TriggerOperationType__c, - TriggerSObjectType__c = logEntryEvent.TriggerSObjectType__c + TriggerSObjectType__c = logEntryEvent.TriggerSObjectType__c, + UniqueId__c = logEntryEvent.TransactionId__c + '-' + logEntryEvent.TransactionEntryNumber__c ); if (String.isNotBlank(logEntryEvent.EntryScenario__c) == true) { @@ -352,21 +351,15 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { logEntry.setOptions(DML_OPTIONS); this.logEntries.add(logEntry); - if (logEntry.EventUuid__c == null) { - logEntriesWithoutUuid.add(logEntry); - } else { - logEntriesWithUuid.add(logEntry); - if (logEntryEvent.Tags__c != null) { - List logEntryTagNames = getTagNames(logEntryEvent.Tags__c); - - this.tagNames.addAll(logEntryTagNames); - this.logEntryEventUuidToTagNames.put(logEntry.EventUuid__c, logEntryTagNames); - } + + if (logEntryEvent.Tags__c != null) { + List logEntryTagNames = getTagNames(logEntryEvent.Tags__c); + this.tagNames.addAll(logEntryTagNames); + this.logEntryEventCompositeKeyToTagNames.put(logEntry.UniqueId__c, logEntryTagNames); } } - List saveResults = LoggerDataStore.getDatabase().insertRecords(logEntriesWithoutUuid); - LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResults); - List upsertResults = LoggerDataStore.getDatabase().upsertRecords(logEntriesWithUuid, Schema.LogEntry__c.EventUuid__c); + + List upsertResults = LoggerDataStore.getDatabase().upsertRecords(this.logEntries, Schema.LogEntry__c.UniqueId__c); LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResults); } @@ -380,13 +373,17 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { if (isRuleCriteriaMet(logEntry, rule) == true) { List configuredTagNames = getTagNames(rule.Tags__c); this.tagNames.addAll(configuredTagNames); - List logEntryTags = logEntryEventUuidToTagNames.get(logEntry.EventUuid__c); + List logEntryTags = new List(); + if (this.logEntryEventCompositeKeyToTagNames.containsKey(logEntry.UniqueId__c) == true) { + logEntryTags = this.logEntryEventCompositeKeyToTagNames.get(logEntry.UniqueId__c); + } + if (logEntryTags == null) { logEntryTags = new List(); } logEntryTags.addAll(configuredTagNames); - this.logEntryEventUuidToTagNames.put(logEntry.EventUuid__c, logEntryTags); + this.logEntryEventCompositeKeyToTagNames.put(logEntry.UniqueId__c, logEntryTags); this.tagNames.addAll(logEntryTags); } } @@ -407,14 +404,11 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { Schema.SObjectType tagAssignmentSObjectType; Set tagAssignments = new Set(); for (LogEntry__c logEntry : this.logEntries) { - if (logEntry.EventUuid__c == null) { + if (this.logEntryEventCompositeKeyToTagNames.containsKey(logEntry.UniqueId__c) == false) { continue; } - List logEntryTagNames = this.logEntryEventUuidToTagNames.get(logEntry.EventUuid__c); - if (logEntryTagNames == null || logEntryEventUuidToTagNames.isEmpty() == true) { - continue; - } + List logEntryTagNames = this.logEntryEventCompositeKeyToTagNames.get(logEntry.UniqueId__c); for (String tagName : logEntryTagNames) { if (LoggerParameter.USE_TOPICS_FOR_TAGS == true) { diff --git a/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml b/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml index 023154cfe..1c942b5d9 100644 --- a/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml +++ b/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml @@ -82,6 +82,12 @@ Record.EntryScenario__c RecordEntryScenario__cField + + + {!Record.EntryScenarioLink__c} + NE + + Facet-cb40f95d-9915-4ba5-815c-f3e53bcc4001 @@ -125,6 +131,22 @@ + + + + uiBehavior + readonly + + Record.UniqueId__c + RecordUniqueId_cField + + + {!Record.UniqueId__c} + NE + + + + @@ -133,6 +155,12 @@ Record.EventUuid__c RecordEventUuid__cField + + + {!Record.EventUuid__c} + NE + + Facet-f419a303-8d53-44e5-8647-63a464804568 @@ -612,6 +640,10 @@ columns Facet-506803d6-0468-4ac1-a044-ede56cf84c05 + + horizontalAlignment + false + label Information @@ -626,6 +658,10 @@ columns Facet-3a75f17f-589a-49f4-bdec-38f730e94676 + + horizontalAlignment + false + label Message Details @@ -640,6 +676,10 @@ columns Facet-2a15cd64-78af-4727-8c6d-2913cb00a278 + + horizontalAlignment + false + label Exception Information @@ -661,6 +701,10 @@ columns Facet-b0b8c0ec-36e3-469b-9106-00d34530d793 + + horizontalAlignment + false + label Database Result @@ -682,6 +726,10 @@ columns Facet-f6d04c17-cbcd-40c6-aa58-c46313ecd8c4 + + horizontalAlignment + false + label Related Record @@ -709,6 +757,10 @@ columns Facet-25eaa065-25af-4efc-9ce5-9d289a0fc3f0 + + horizontalAlignment + false + label HTTP Request @@ -729,6 +781,10 @@ columns Facet-6395ceae-5694-468a-911f-714456910736 + + horizontalAlignment + false + label HTTP Response @@ -945,6 +1001,10 @@ columns Facet-4fa5f475-f3a7-4ac0-b1cd-8285d7b369c7 + + horizontalAlignment + false + label Limits @@ -1441,6 +1501,10 @@ columns Facet-defe921e-2975-4026-bfa5-1fe30baba592 + + horizontalAlignment + false + label Tags @@ -1462,6 +1526,10 @@ columns Facet-a417c39b-b395-4d13-a87d-2d5bbb9d9d77 + + horizontalAlignment + false + label Apex Class Information @@ -1488,6 +1556,10 @@ columns Facet-5f20b7f6-e40f-49b2-905b-5e2ca6c609e9 + + horizontalAlignment + false + label Flow Information @@ -1509,6 +1581,10 @@ columns Facet-6b39517d-52f9-42f2-bf33-d392592baaa4 + + horizontalAlignment + false + label Lightning Component Information @@ -1530,6 +1606,10 @@ columns Facet-81767854-f045-476a-a24f-aa790ad2f249 + + horizontalAlignment + false + label Browser Information diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/UniqueId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/UniqueId__c.field-meta.xml new file mode 100644 index 000000000..663dca1c8 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/UniqueId__c.field-meta.xml @@ -0,0 +1,14 @@ + + + UniqueId__c + false + Composite key that will hold the value of the TransactionId + TransactionEntryNumber + true + + 255 + false + false + false + Text + true + diff --git a/nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml index 4e485220f..eceeeddf4 100644 --- a/nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml +++ b/nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml @@ -818,6 +818,11 @@ LogEntry__c.Trigger__c true + + true + LogEntryTag__c.UniqueId__c + true + false Log__c.ApiReleaseNumber__c diff --git a/nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml index adac71f09..59b3fbc8c 100644 --- a/nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml +++ b/nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml @@ -598,6 +598,11 @@ LogEntry__c.Trigger__c true + + false + LogEntryTag__c.UniqueId__c + true + false Log__c.ApiReleaseNumber__c diff --git a/nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml index c15929974..c99765bc2 100644 --- a/nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml +++ b/nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml @@ -742,6 +742,11 @@ LogEntry__c.Trigger__c true + + false + LogEntryTag__c.UniqueId__c + true + false Log__c.ApiReleaseNumber__c diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls index 753a24eeb..86f42b72f 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.11.6'; + private static final String CURRENT_VERSION_NUMBER = 'v4.11.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(); 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 f12e6563c..dd131b097 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.11.6'; +const CURRENT_VERSION_NUMBER = 'v4.11.7'; export default class Logger extends LightningElement { #loggerService = createLoggerService(); diff --git a/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls index c5defc1d8..e6d60a866 100644 --- a/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls @@ -306,13 +306,15 @@ private class LogEntryEventHandler_Tests { LoggerScenario__c existingLogScenario = new LoggerScenario__c(UniqueId__c = 'hello, world'); insert existingLogScenario; System.Assert.areEqual(1, [SELECT COUNT() FROM LoggerScenario__c]); - LogEntryEvent__e firstLogEntryEvent = createLogEntryEvent(); - firstLogEntryEvent.EntryScenario__c = null; - firstLogEntryEvent.TransactionScenario__c = existingLogScenario.UniqueId__c; - LogEntryEvent__e secondLogEntryEvent = createLogEntryEvent(); - secondLogEntryEvent.EntryScenario__c = null; - secondLogEntryEvent.TransactionScenario__c = existingLogScenario.UniqueId__c; - List logEntryEvents = new List{ firstLogEntryEvent, secondLogEntryEvent }; + List logEntryEvents = new List(); + for (Integer i = 0; i < 2; i++) { + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.TransactionEntryNumber__c = i; + logEntryEvent.TransactionId__c = '123-456'; + logEntryEvent.EntryScenario__c = null; + logEntryEvent.TransactionScenario__c = existingLogScenario.UniqueId__c; + logEntryEvents.add(logEntryEvent); + } List saveResults = LoggerMockDataStore.getEventBus().publishRecords(logEntryEvents); LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); @@ -350,9 +352,11 @@ private class LogEntryEventHandler_Tests { String newScenario = 'some new value'; System.Assert.areEqual(1, [SELECT COUNT() FROM LoggerScenario__c]); LogEntryEvent__e firstLogEntryEvent = createLogEntryEvent(); + firstLogEntryEvent.TransactionEntryNumber__c = 1; firstLogEntryEvent.EntryScenario__c = existingLoggerScenario.UniqueId__c; firstLogEntryEvent.TransactionScenario__c = null; LogEntryEvent__e secondLogEntryEvent = createLogEntryEvent(); + secondLogEntryEvent.TransactionEntryNumber__c = 2; secondLogEntryEvent.EntryScenario__c = newScenario; secondLogEntryEvent.TransactionScenario__c = null; List logEntryEvents = new List{ firstLogEntryEvent, secondLogEntryEvent }; @@ -394,8 +398,10 @@ private class LogEntryEventHandler_Tests { System.Assert.areEqual(1, [SELECT COUNT() FROM LoggerScenario__c]); LogEntryEvent__e firstLogEntryEvent = createLogEntryEvent(); firstLogEntryEvent.EntryScenario__c = existingLoggerScenario.UniqueId__c; + firstLogEntryEvent.TransactionEntryNumber__c = 1; firstLogEntryEvent.TransactionScenario__c = newTransactionScenario; LogEntryEvent__e secondLogEntryEvent = createLogEntryEvent(); + secondLogEntryEvent.TransactionEntryNumber__c = 2; secondLogEntryEvent.EntryScenario__c = newEntryScenario; secondLogEntryEvent.TransactionScenario__c = newTransactionScenario; List logEntryEvents = new List{ firstLogEntryEvent, secondLogEntryEvent }; @@ -1153,6 +1159,33 @@ private class LogEntryEventHandler_Tests { validateLogEntryFields(logEntryEvent, logEntry); } + @IsTest + static void it_should_save_data_when_saving_with_synchronous_dml() { + System.Assert.areEqual(0, [SELECT COUNT() FROM Log__c], 'Test has started under the wrong conditions'); + System.Assert.areEqual(0, [SELECT COUNT() FROM LogEntry__c], 'Test has started under the wrong conditions'); + System.Assert.areEqual(0, [SELECT COUNT() FROM LogEntryTag__c], 'Test has started under the wrong conditions'); + System.Assert.areEqual(0, [SELECT COUNT() FROM LoggerTag__c], 'Test has started under the wrong conditions'); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + String exampleTag = 'Some tag'; + + System.Test.startTest(); + LogEntryEventBuilder builder = Logger.info('some INFO message').addTag(exampleTag); + System.Assert.areEqual(1, Logger.getBufferSize()); + Logger.setSaveMethod(Logger.SaveMethod.SYNCHRONOUS_DML); + System.Assert.areEqual(Logger.getSaveMethod(), Logger.SaveMethod.SYNCHRONOUS_DML, 'Save method should be SYNCHRONOUS_DML'); + Logger.saveLog(); + System.Assert.areEqual(0, Logger.getBufferSize()); + System.Test.stopTest(); + + System.Assert.areEqual(1, [SELECT COUNT() FROM Log__c], '1 matching Log__c record should have been generated'); + System.Assert.areEqual( + 1, + [SELECT COUNT() FROM LogEntry__c WHERE LoggingLevel__c = :System.LoggingLevel.INFO.name()], + '1 matching LogEntry__c record should have been generated' + ); + System.Assert.areEqual(1, [SELECT COUNT() FROM LoggerTag__c WHERE Name = :exampleTag], '1 matching LoggerTag__c record should have been generated'); + } + private static LogEntryEvent__e createLogEntryEvent() { // The data builder class handles populating field values, but for some fields, // certain values are expected (e.g., LoggedById__c should have a valid user ID), diff --git a/package.json b/package.json index 3e68a4b60..2a36c4005 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nebula-logger", - "version": "4.11.6", + "version": "4.11.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 b29634364..6c7dec58a 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.11.6.NEXT", - "versionName": "New Method Logger.setAsyncContext()", - "versionDescription": "Added a method Logger.setAsyncContext + new fields on LogEntryEvent__e and Log__c to track the current transacation's async context", + "versionNumber": "4.11.7.NEXT", + "versionName": "Bugfix for Tags Not Saving for Save Method SYNCHRONOUS_DML", + "versionDescription": "Added a new composite key field, LogEntry__c.UniqueId__c, to fix a bug where tagging data would not save properly when using the save method SYNCHRONOUS_DML", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases", "unpackagedMetadata": { "path": "./nebula-logger/extra-tests" @@ -154,6 +154,7 @@ "Nebula Logger - Core@4.11.4-removed-chatter-dependencies": "04t5Y000001HZdPQAW", "Nebula Logger - Core@4.11.5-custom-index-for-log-retention-date": "04t5Y000001HZdZQAW", "Nebula Logger - Core@4.11.6-new-method-logger.setasynccontext()": "04t5Y000001HZfGQAW", + "Nebula Logger - Core@4.11.7-bugfix-for-tags-not-saving-for-save-method-synchronous_dml": "04t5Y000001HZfaQAG", "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",