diff --git a/README.md b/README.md index 901dc3f7c..2e8815dac 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@ The most robust logger for Salesforce. Works with Apex, Lightning Components, Fl ## Unlocked Package - v4.12.0 -[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk1wQAC) -[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk1wQAC) +[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk4bQAC) +[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mk4bQAC) [![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/) -`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001Mk1wQAC` +`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001Mk4bQAC` -`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001Mk1wQAC` +`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001Mk4bQAC` --- diff --git a/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls b/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls index 6fba7138d..a598b3742 100644 --- a/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls +++ b/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls @@ -108,12 +108,28 @@ public without sharing class LoggerEmailSender { sendEmail(messages); } + private static String getErrorMessageFromDatabaseError(Database.Error error) { + List messageParts = new List(); + + // Add the status code + messageParts.add('StatusCode: ' + error.getStatusCode()); + // Add the message + messageParts.add('Message: ' + error.getMessage()); + // Add the fields if available + List fields = error.getFields(); + if (fields?.isEmpty() == false) { + messageParts.add('Field(s): [' + String.join(fields, ', ') + ']'); + } + + return String.join(messageParts, ', '); + } + private static List getErrorMessages(List saveResults) { List errorMessages = new List(); for (Database.SaveResult result : saveResults) { if (result.isSuccess() == false) { for (Database.Error error : result.getErrors()) { - errorMessages.add(error.getMessage()); + errorMessages.add(getErrorMessageFromDatabaseError(error)); } } } @@ -125,7 +141,7 @@ public without sharing class LoggerEmailSender { for (Database.UpsertResult result : upsertResults) { if (result.isSuccess() == false) { for (Database.Error error : result.getErrors()) { - errorMessages.add(error.getMessage()); + errorMessages.add(getErrorMessageFromDatabaseError(error)); } } } @@ -161,7 +177,7 @@ public without sharing class LoggerEmailSender { } private static String buildHtmlBody(Schema.SObjectType sobjectType, List errorMessages) { - final String emailBodyTemplate = 'Logger failed to save {0} {1} records for {2} (User ID: {3})

Error Messages:
    {4}
'; + final String emailBodyTemplate = 'Logger failed to save {0} {1} records for {2} (User ID: {3})

Errors:
    {4}
'; final String formattedErrorMessages = '
  • ' + String.join(errorMessages, '
  • ') + '
  • '; List emailBodyInputs = new List{ errorMessages.size(), diff --git a/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls b/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls index 5848bf841..23d2b718b 100644 --- a/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls +++ b/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls @@ -143,7 +143,7 @@ public class LoggerMockDataCreator { return (Database.SaveResult) JSON.deserialize('{"success": true, "id": "' + recordId + '"}', Database.SaveResult.class); } else { return (Database.SaveResult) JSON.deserialize( - '{"success":false,"errors":[{"message": "Could not save...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION"}]}', + '{"success":false,"errors":[{"message": "Could not save...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION", "fields": ["Name"]}]}', Database.SaveResult.class ); } @@ -172,7 +172,7 @@ public class LoggerMockDataCreator { return (Database.UndeleteResult) JSON.deserialize('{"success": true, "id": "' + recordId + '"}', Database.UndeleteResult.class); } else { return (Database.UndeleteResult) JSON.deserialize( - '{"success":false,"errors":[{"message": "Could not undelete...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION"}]}', + '{"success":false,"errors":[{"message": "Could not undelete...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION", "fields": ["Name"]}]}', Database.UndeleteResult.class ); } @@ -208,7 +208,7 @@ public class LoggerMockDataCreator { return (Database.UpsertResult) JSON.deserialize( '{"success":false, "created":' + isCreated + - ', "errors":[{"message": "Could not upsert...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION"}]}', + ', "errors":[{"message": "Could not upsert...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION", "fields": ["Name"]}]}', Database.UpsertResult.class ); } diff --git a/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls index 548700232..d3e0e64d1 100644 --- a/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls @@ -54,11 +54,16 @@ private class LoggerEmailSender_Tests { Database.SaveResult saveResultWithError = LoggerMockDataCreator.createDatabaseSaveResult(false); LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, new List{ saveResultWithError }); - System.Assert.areEqual( - true, + System.Assert.isTrue( LoggerEmailSender.SENT_EMAILS.get(0).getHtmlBody().contains(saveResultWithError.errors.get(0).getMessage()), 'Email message should contain SaveResult error message' ); + List errorFields = saveResultWithError.getErrors().get(0).getFields(); + String expectedFieldsError = 'Field(s): [' + String.join(errorFields, ', ') + ']'; + System.Assert.isTrue( + LoggerEmailSender.SENT_EMAILS.get(0).getHtmlBody().contains(expectedFieldsError), + 'Email message should contain SaveResult error fields: ' + expectedFieldsError + ); if (LoggerEmailSender.IS_EMAIL_DELIVERABILITY_AVAILABLE) { System.Assert.areEqual(1, System.Limits.getEmailInvocations(), 'Email should have been sent'); } else { @@ -104,11 +109,16 @@ private class LoggerEmailSender_Tests { Database.UpsertResult upsertResultWithError = LoggerMockDataCreator.createDatabaseUpsertResult(false, false); LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, new List{ upsertResultWithError }); - System.Assert.areEqual( - true, + System.Assert.isTrue( LoggerEmailSender.SENT_EMAILS.get(0).getHtmlBody().contains(upsertResultWithError.errors.get(0).getMessage()), 'Email message should contain UpsertResult error message' ); + List errorFields = upsertResultWithError.getErrors().get(0).getFields(); + String expectedFieldsError = 'Field(s): [' + String.join(errorFields, ', ') + ']'; + System.Assert.isTrue( + LoggerEmailSender.SENT_EMAILS.get(0).getHtmlBody().contains(expectedFieldsError), + 'Email message should contain UpsertResult error fields: ' + expectedFieldsError + ); if (LoggerEmailSender.IS_EMAIL_DELIVERABILITY_AVAILABLE) { System.Assert.areEqual(1, System.Limits.getEmailInvocations(), 'Email should have been sent'); } else { diff --git a/nebula-logger/managed-package/sfdx-project.json b/nebula-logger/managed-package/sfdx-project.json index 01c663b73..6690be9e2 100644 --- a/nebula-logger/managed-package/sfdx-project.json +++ b/nebula-logger/managed-package/sfdx-project.json @@ -10,10 +10,10 @@ "definitionFile": "./config/scratch-orgs/base-scratch-def.json", "postInstallScript": "LoggerInstallHandler", "ancestorVersion": "HIGHEST", - "versionNumber": "4.12.0.NEXT", - "versionName": "Winter '24 Release", - "versionDescription": "View the v4.12.0 milestone in GitHub for the list of changes - https://github.com/jongpie/NebulaLogger/milestone/12?closed=1", - "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases/tag/v4.11.0" + "versionNumber": "4.13.0.NEXT", + "versionName": "Spring '24 Release", + "versionDescription": "View the v4.13.0 milestone in GitHub for the list of changes - https://github.com/jongpie/NebulaLogger/milestone/13?closed=1", + "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases/tag/v4.13.0" } ], "packageAliases": { diff --git a/sfdx-project.json b/sfdx-project.json index c6a3e9dae..e4c288a49 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.0.NEXT", - "versionName": "Winter '24 Release", - "versionDescription": "Updated all metadata to API v59.0, fixed a bug with logging Map, added new formula fields on Log__c & LogEntry__c for scenario names, added more metadata to the managed package", + "versionNumber": "4.12.1.NEXT", + "versionName": "Improved Error Emails", + "versionDescription": "Updated error emails (sent by LoggerEmailSender) to include all Database.Error fields", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases", "unpackagedMetadata": { "path": "./nebula-logger/extra-tests" @@ -161,6 +161,7 @@ "Nebula Logger - Core@4.11.11-reduced-usage-of-email-limits-consumption-in-loggeremailsender": "04t5Y000001Oih7QAC", "Nebula Logger - Core@4.11.12-bugfix-for-lightning-component-entries-not-always-saving": "04t5Y000001Mjx5QAC", "Nebula Logger - Core@4.12.0-winter-'24-release": "04t5Y000001Mk1wQAC", + "Nebula Logger - Core@4.12.1-improved-error-emails": "04t5Y000001Mk4bQAC", "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",