+
+
+
- System Information
+ {section.label}
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js
index 01fbe99a3..24c7aa54a 100644
--- a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js
+++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js
@@ -9,6 +9,7 @@ import { ShowToastEvent } from 'lightning/platformShowToastEvent';
// LoggerSettings__c metadata
import LOGGER_SETTINGS_SCHEMA from './loggerSettingsSchema';
+import { generatePageLayout } from './loggerSettingsPageLayout';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import canUserModifyLoggerSettings from '@salesforce/apex/LoggerSettingsController.canUserModifyLoggerSettings';
import getPicklistOptions from '@salesforce/apex/LoggerSettingsController.getPicklistOptions';
@@ -40,7 +41,7 @@ export default class LoggerSettings extends LightningElement {
// LoggerSettings__c metadata
canUserModifyLoggerSettings;
loggerSettingsPicklistOptions;
- _loggerSettingsFields;
+ _sobjectDescribe;
// LoggerSettings__c data
records;
@@ -52,20 +53,19 @@ export default class LoggerSettings extends LightningElement {
this.showLoadingSpinner = true;
Promise.all([getOrganization(), getPicklistOptions()])
- .then(([organization, loggerSettingsPicklistOptions]) => {
- this.organization = organization;
- this.loggerSettingsPicklistOptions = loggerSettingsPicklistOptions;
+ .then(([organizationRecord, apexPicklistOptions]) => {
+ this.organization = organizationRecord;
+ this.loggerSettingsPicklistOptions = this._parsePicklistOptions(apexPicklistOptions);
})
.catch(this._handleError);
-
this.loadSettingsRecords();
this.showLoadingSpinner = false;
}
- @wire(getObjectInfo, { objectApiName: LOGGER_SETTINGS_SCHEMA.sobject })
+ @wire(getObjectInfo, { objectApiName: LOGGER_SETTINGS_SCHEMA.apiName })
getLoggerSettingsObjectInfo({ data }) {
if (data) {
- this._loggerSettingsFields = data.fields;
+ this._sobjectDescribe = data;
canUserModifyLoggerSettings().then(result => {
this.canUserModifyLoggerSettings = result;
this._loadTableColumns();
@@ -199,45 +199,24 @@ export default class LoggerSettings extends LightningElement {
}
// Getters for each LoggerSettings__c field describes & data - these handle dealing with using a namespace for the package
+ // TODO - this is a legacy approach where separate getters were used for each field - the audit fields & "general info" fields still use this approach
+ // but should be updated to leverage the new approach, loggerSettingsPageLayout.js
+ get layoutData() {
+ return generatePageLayout(this._sobjectDescribe, this.loggerSettingsPicklistOptions, this.isReadOnlyMode, this._currentRecord);
+ }
+
get createdByIdField() {
return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.CreatedById, 'createdByUsername');
}
+
get createdDateField() {
return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.CreatedDate);
}
- get defaultLogShareAccessLevelField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.DefaultLogShareAccessLevel__c);
- }
-
- get defaultNumberOfDaysToRetainLogsField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.DefaultNumberOfDaysToRetainLogs__c);
- }
-
- get defaultSaveMethodField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.DefaultSaveMethod__c);
- }
-
- get isAnonymousModeEnabledField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.IsAnonymousModeEnabled__c);
- }
-
- get isApexSystemDebugLoggingEnabledField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.IsApexSystemDebugLoggingEnabled__c);
- }
-
- get isDataMaskingEnabledField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.IsDataMaskingEnabled__c);
- }
-
get isEnabledField() {
return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.IsEnabled__c);
}
- get isJavaScriptConsoleLoggingEnabledField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.IsJavaScriptConsoleLoggingEnabled__c);
- }
-
get lastModifiedByIdField() {
return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.LastModifiedById, 'lastModifiedByUsername');
}
@@ -258,10 +237,6 @@ export default class LoggerSettings extends LightningElement {
return this._loadField('setupOwnerType', 'setupOwnerType', 'Setup Location');
}
- get stripInaccessibleRecordFieldsField() {
- return this._loadField(LOGGER_SETTINGS_SCHEMA.fields.StripInaccessibleRecordFields__c);
- }
-
createNewRecord() {
createRecord()
.then(result => {
@@ -352,13 +327,15 @@ export default class LoggerSettings extends LightningElement {
const tableColumnNames = [
LOGGER_SETTINGS_SCHEMA.fields.IsEnabled__c,
LOGGER_SETTINGS_SCHEMA.fields.LoggingLevel__c,
- LOGGER_SETTINGS_SCHEMA.fields.IsDataMaskingEnabled__c,
+ LOGGER_SETTINGS_SCHEMA.fields.IsSavingEnabled__c,
LOGGER_SETTINGS_SCHEMA.fields.DefaultSaveMethod__c,
+ LOGGER_SETTINGS_SCHEMA.fields.IsPlatformEventStorageEnabled__c,
+ LOGGER_SETTINGS_SCHEMA.fields.IsDataMaskingEnabled__c,
LOGGER_SETTINGS_SCHEMA.fields.DefaultNumberOfDaysToRetainLogs__c,
LOGGER_SETTINGS_SCHEMA.fields.DefaultLogShareAccessLevel__c
];
for (let i = 0; i < tableColumnNames.length; i++) {
- const field = this._loggerSettingsFields[tableColumnNames[i]];
+ const field = this._sobjectDescribe.fields[tableColumnNames[i]];
const column = {
fieldName: field.apiName,
label: field.label,
@@ -387,14 +364,21 @@ export default class LoggerSettings extends LightningElement {
});
}
+ _parsePicklistOptions(apexPicklistOptions) {
+ let picklistOptions = {};
+
+ return apexPicklistOptions;
+ }
+
+ // TODO delete??
_loadField(fieldApiName, recordFieldApiName, recordFieldLabel) {
if (!recordFieldApiName) {
recordFieldApiName = fieldApiName;
}
let fieldDescribe;
- if (fieldApiName && this._loggerSettingsFields[fieldApiName]) {
- fieldDescribe = { ...this._loggerSettingsFields[fieldApiName] };
+ if (fieldApiName && this._sobjectDescribe.fields[fieldApiName]) {
+ fieldDescribe = { ...this._sobjectDescribe.fields[fieldApiName] };
} else {
fieldDescribe = { apiName: fieldApiName };
}
diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js
new file mode 100644
index 000000000..3c6c9bb18
--- /dev/null
+++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js
@@ -0,0 +1,141 @@
+/*************************************************************************************************
+ * This file is part of the Nebula Logger project, released under the MIT License. *
+ * See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. *
+ ************************************************************************************************/
+
+import LOGGER_SETTINGS_SCHEMA from './loggerSettingsSchema';
+
+const PAGE_LAYOUT_CONFIG = {
+ sections: [
+ {
+ key: 'developerSettings',
+ label: 'Developer Settings',
+ showInReadOnlyMode: true,
+ showInEditMode: true,
+ columns: [
+ {
+ fieldApiNames: [
+ LOGGER_SETTINGS_SCHEMA.fields.IsSavingEnabled__c,
+ LOGGER_SETTINGS_SCHEMA.fields.DefaultSaveMethod__c,
+ LOGGER_SETTINGS_SCHEMA.fields.IsPlatformEventStorageEnabled__c
+ ],
+ size: 6
+ },
+ {
+ fieldApiNames: [
+ LOGGER_SETTINGS_SCHEMA.fields.IsApexSystemDebugLoggingEnabled__c,
+ LOGGER_SETTINGS_SCHEMA.fields.IsJavaScriptConsoleLoggingEnabled__c
+ ],
+ size: 6
+ }
+ ]
+ },
+ {
+ key: 'securitySettings',
+ label: 'Security Settings',
+ showInReadOnlyMode: true,
+ showInEditMode: true,
+ columns: [
+ { fieldApiNames: [LOGGER_SETTINGS_SCHEMA.fields.IsDataMaskingEnabled__c], size: 6 },
+ {
+ fieldApiNames: [LOGGER_SETTINGS_SCHEMA.fields.StripInaccessibleRecordFields__c, LOGGER_SETTINGS_SCHEMA.fields.IsAnonymousModeEnabled__c],
+ size: 6
+ }
+ ]
+ },
+ {
+ key: 'logManagementSettings',
+ label: 'Log Management Settings',
+ showInReadOnlyMode: true,
+ showInEditMode: true,
+ columns: [
+ { fieldApiNames: [LOGGER_SETTINGS_SCHEMA.fields.DefaultNumberOfDaysToRetainLogs__c], size: 6 },
+ { fieldApiNames: [LOGGER_SETTINGS_SCHEMA.fields.DefaultLogShareAccessLevel__c], size: 6 }
+ ]
+ },
+ {
+ key: 'systemInformation',
+ label: 'System Information',
+ showInReadOnlyMode: true,
+ showInEditMode: false,
+ columns: [
+ { fieldApiNames: [LOGGER_SETTINGS_SCHEMA.fields.CreatedById, LOGGER_SETTINGS_SCHEMA.fields.CreatedDate], size: 6 },
+ { fieldApiNames: [LOGGER_SETTINGS_SCHEMA.fields.LastModifiedById, LOGGER_SETTINGS_SCHEMA.fields.LastModifiedDate], size: 6 }
+ ]
+ }
+ ]
+};
+
+const LoggerSettingsPageLayout = class {
+ constructor(sobjectDescribe, apexPicklistOptions, isReadOnlyMode, record) {
+ const picklistOptions = this._parsePicklistOptions(apexPicklistOptions);
+
+ this._buildPageLayoutSectionFields(sobjectDescribe, picklistOptions, isReadOnlyMode, record);
+ }
+
+ _parsePicklistOptions(apexPicklistOptions) {
+ // TODO - long term, this feels like the wrong place for this mapping to live, but it'll live here for now
+ const picklistOptions = {
+ [LOGGER_SETTINGS_SCHEMA.fields.LoggingLevel__c]: apexPicklistOptions.loggingLevelOptions,
+ [LOGGER_SETTINGS_SCHEMA.fields.DefaultSaveMethod__c]: apexPicklistOptions.saveMethodOptions,
+ [LOGGER_SETTINGS_SCHEMA.fields.DefaultLogShareAccessLevel__c]: apexPicklistOptions.shareAccessLevelOptions
+ };
+
+ return picklistOptions;
+ }
+
+ _buildPageLayoutSectionFields(sobjectDescribe, picklistOptions, isReadOnlyMode, record) {
+ this.sections = [];
+
+ let layoutConfigSections = [...PAGE_LAYOUT_CONFIG.sections];
+ layoutConfigSections.forEach(section => {
+ section.show = (section.showInReadOnlyMode && isReadOnlyMode) || (section.showInEditMode && !isReadOnlyMode);
+
+ if (!section.show) {
+ return;
+ }
+
+ section.columns?.forEach(column => {
+ column.key = Date.now() + Math.floor(Math.random() * 13);
+ column.fields = [];
+ column.fieldApiNames.forEach(fieldApiName => {
+ let field = { ...sobjectDescribe.fields[fieldApiName] };
+ field.value = record[fieldApiName];
+ this._setFieldTypeDetails(field, picklistOptions);
+
+ column.fields.push(field);
+ });
+ });
+ this.sections.push(section);
+ });
+ }
+
+ _setFieldTypeDetails(field, picklistOptions) {
+ // Picklists are handled differently, since these aren't actually picklist fields
+ // (Custom settings objects don't have picklist fields - custom Apex is used for generating picklist options)
+ if (picklistOptions[field.apiName]) {
+ field.picklistOptions = picklistOptions[field.apiName];
+ field.type = 'picklist';
+ field.useCombobox = true;
+
+ return;
+ }
+
+ field.useCombobox = false;
+ switch (field.dataType) {
+ case 'Boolean':
+ field.type = 'checkbox';
+ break;
+ case 'Double':
+ field.type = 'number';
+ break;
+ default:
+ field.type = 'text';
+ break;
+ }
+ }
+};
+
+export function generatePageLayout(sobjectDescribe, apexPicklistOptions, isReadOnlyMode, record) {
+ return new LoggerSettingsPageLayout(sobjectDescribe, apexPicklistOptions, isReadOnlyMode, record);
+}
diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsSchema.js b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsSchema.js
index ae0c50046..599bc0c5d 100644
--- a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsSchema.js
+++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsSchema.js
@@ -14,6 +14,8 @@ import IS_APEX_SYSTEM_DEBUG_LOGGING_ENABLED_FIELD from '@salesforce/schema/Logge
import IS_DATA_MASKING_ENABLED_FIELD from '@salesforce/schema/LoggerSettings__c.IsDataMaskingEnabled__c';
import IS_ENABLED_FIELD from '@salesforce/schema/LoggerSettings__c.IsEnabled__c';
import IS_JAVA_SCRIPT_CONSOLE_LOGGING_ENABLED_FIELD from '@salesforce/schema/LoggerSettings__c.IsJavaScriptConsoleLoggingEnabled__c';
+import IS_SAVING_ENABLED_FIELD from '@salesforce/schema/LoggerSettings__c.IsSavingEnabled__c';
+import IS_PLATFORM_EVENT_STORAGE_ENABLED_FIELD from '@salesforce/schema/LoggerSettings__c.IsPlatformEventStorageEnabled__c';
import LAST_MODIFIED_BY_ID_FIELD from '@salesforce/schema/LoggerSettings__c.LastModifiedById';
import LAST_MODIFIED_DATE_FIELD from '@salesforce/schema/LoggerSettings__c.LastModifiedDate';
import LOGGING_LEVEL_FIELD from '@salesforce/schema/LoggerSettings__c.LoggingLevel__c';
@@ -21,7 +23,7 @@ import STRIP_INACCESSIBLE_RECORD_FIELDS_FIELD from '@salesforce/schema/LoggerSet
import SETUP_OWNER_ID_FIELD from '@salesforce/schema/LoggerSettings__c.SetupOwnerId';
const LOGGER_SETTINGS_SCHEMA = {
- sobject: LOGGER_SETTINGS_OBJECT,
+ apiName: LOGGER_SETTINGS_OBJECT.objectApiName,
fields: {
CreatedById: CREATED_BY_ID_FIELD.fieldApiName,
CreatedDate: CREATED_DATE_FIELD.fieldApiName,
@@ -33,6 +35,8 @@ const LOGGER_SETTINGS_SCHEMA = {
IsDataMaskingEnabled__c: IS_DATA_MASKING_ENABLED_FIELD.fieldApiName,
IsEnabled__c: IS_ENABLED_FIELD.fieldApiName,
IsJavaScriptConsoleLoggingEnabled__c: IS_JAVA_SCRIPT_CONSOLE_LOGGING_ENABLED_FIELD.fieldApiName,
+ IsPlatformEventStorageEnabled__c: IS_PLATFORM_EVENT_STORAGE_ENABLED_FIELD.fieldApiName,
+ IsSavingEnabled__c: IS_SAVING_ENABLED_FIELD.fieldApiName,
LastModifiedById: LAST_MODIFIED_BY_ID_FIELD.fieldApiName,
LastModifiedDate: LAST_MODIFIED_DATE_FIELD.fieldApiName,
LoggingLevel__c: LOGGING_LEVEL_FIELD.fieldApiName,
diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls
index 881ad1026..32cb65394 100644
--- a/nebula-logger/core/main/logger-engine/classes/Logger.cls
+++ b/nebula-logger/core/main/logger-engine/classes/Logger.cls
@@ -2509,7 +2509,7 @@ global with sharing class Logger {
*/
@SuppressWarnings('PMD.NcssMethodCount')
global static void saveLog(SaveMethod saveMethod) {
- if (LOG_ENTRIES_BUFFER.isEmpty()) {
+ if (LOG_ENTRIES_BUFFER.isEmpty() || getUserSettings().IsSavingEnabled__c == false) {
return;
}
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 81f12ce6f..f1240d83e 100644
--- a/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls
+++ b/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls
@@ -27,12 +27,45 @@ private class LogEntryEventHandler_Tests {
Test.stopTest();
}
+ @IsTest
+ static void it_should_not_create_log_or_log_entry_data_when_platform_event_storage_is_disabled() {
+ Integer countOfLogs = [SELECT COUNT() FROM Log__c];
+ System.assertEquals(0, countOfLogs);
+ Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c];
+ System.assertEquals(0, countOfLogEntries);
+
+ Logger.getUserSettings().IsSavingEnabled__c = true;
+ LoggerSettings__c settings = Logger.getUserSettings();
+ settings.IsPlatformEventStorageEnabled__c = false;
+ upsert settings;
+ LogEntryEvent__e logEntryEvent = new LogEntryEvent__e(
+ EpochTimestamp__c = System.now().getTime(),
+ LoggedById__c = UserInfo.getUserId(),
+ Message__c = 'my message',
+ Timestamp__c = System.now(),
+ TransactionEntryNumber__c = 1,
+ TransactionId__c = '123-456-789-0'
+ );
+
+ Test.startTest();
+ Database.SaveResult saveResult = EventBus.publish(logEntryEvent);
+ Test.stopTest();
+
+ System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors());
+
+ countOfLogs = [SELECT COUNT() FROM Log__c];
+ System.assertEquals(0, countOfLogs);
+ countOfLogEntries = [SELECT COUNT() FROM LogEntry__c];
+ System.assertEquals(0, countOfLogEntries);
+ }
+
@IsTest
static void it_should_normalize_simple_event_data_into_log_and_log_entry() {
String transactionId = '123-456-789-0';
LogEntryEvent__e logEntryEvent = new LogEntryEvent__e(
EpochTimestamp__c = System.now().getTime(),
+ LoggedById__c = UserInfo.getUserId(),
Message__c = 'my message',
Timestamp__c = System.now(),
TransactionEntryNumber__c = 1,
@@ -99,6 +132,7 @@ private class LogEntryEventHandler_Tests {
LimitsSoslSearchesUsed__c = 123,
Locale__c = 'es-ES',
LoggerVersionNumber__c = 'v4.6.10',
+ LoggedById__c = UserInfo.getUserId(),
LoggingLevel__c = 'DEBUG',
LoggingLevelOrdinal__c = 9,
LoginDomain__c = 'https://fake.my.salesforce.com',
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 bb013944b..fa8cf1521 100644
--- a/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls
+++ b/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls
@@ -685,6 +685,36 @@ private class Logger_Tests {
System.assertEquals(2, Logger.getBufferSize());
}
+ @IsTest
+ static void it_should_not_save_when_saving_is_disabled() {
+ Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c];
+ System.assertEquals(0, countOfLogEntries);
+
+ setUserLoggingLevel(LoggingLevel.DEBUG);
+
+ Logger.getUserSettings().IsSavingEnabled__c = false;
+
+ System.assertEquals(Logger.SaveMethod.EVENT_BUS, Logger.transactionSaveMethod);
+
+ Logger.debug('test log entry');
+ Logger.debug('another test log entry');
+
+ System.assertEquals(0, Limits.getPublishImmediateDml());
+
+ Test.startTest();
+
+ Logger.saveLog();
+ System.assertEquals(0, Limits.getPublishImmediateDml());
+ System.assertEquals(0, Limits.getQueueableJobs());
+ System.assertEquals(0, Limits.getCallouts());
+ System.assertEquals(0, Limits.getDmlStatements());
+
+ Test.stopTest();
+
+ countOfLogEntries = [SELECT COUNT() FROM LogEntry__c];
+ System.assertEquals(0, countOfLogEntries);
+ }
+
@IsTest
static void it_should_save_via_event_bus_when_defaulted() {
Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c];