diff --git a/README.md b/README.md
index 7c4c40506..a26961636 100644
--- a/README.md
+++ b/README.md
@@ -5,13 +5,13 @@
The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.
-## Unlocked Package - v4.10.1
+## Unlocked Package - v4.10.2
-[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015nYaQAI)
-[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015nYaQAI)
+[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000023SAGQA2)
+[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000023SAGQA2)
[![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/)
-`sfdx package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015nYaQAI`
+`sfdx package install --wait 20 --security-type AdminsOnly --package 04t5Y0000023S8jQAE`
## Managed Package - v4.10.0
diff --git a/docs/lightning-components/LogEntryBuilder.md b/docs/lightning-components/LogEntryBuilder.md
index aeac35a00..39be58ffd 100644
--- a/docs/lightning-components/LogEntryBuilder.md
+++ b/docs/lightning-components/LogEntryBuilder.md
@@ -5,7 +5,7 @@
**Kind**: global class
- [LogEntryBuilder](#LogEntryBuilder)
- - [new LogEntryBuilder(loggingLevel, shouldSave, isConsoleLoggingEnabled)](#new_LogEntryBuilder_new)
+ - [new LogEntryBuilder(loggingLevel, isConsoleLoggingEnabled)](#new_LogEntryBuilder_new)
- [.setMessage(message)](#LogEntryBuilder+setMessage) [LogEntryBuilder](#LogEntryBuilder)
- [.setRecordId(recordId)](#LogEntryBuilder+setRecordId) [LogEntryBuilder](#LogEntryBuilder)
- [.setRecord(record)](#LogEntryBuilder+setRecord) [LogEntryBuilder](#LogEntryBuilder)
@@ -15,7 +15,7 @@
-### new LogEntryBuilder(loggingLevel, shouldSave, isConsoleLoggingEnabled)
+### new LogEntryBuilder(loggingLevel, isConsoleLoggingEnabled)
Constructor used to generate each JavaScript-based log entry event
This class is the JavaScript-equivalent of the Apex class `LogEntryBuilder`
@@ -23,7 +23,6 @@ This class is the JavaScript-equivalent of the Apex class `LogEntryBuilder`
| Param | Type | Description |
| ----------------------- | -------------------- | ------------------------------------------------------------------------------- |
| loggingLevel | String | The `LoggingLevel` enum to use for the builder's instance of `LogEntryEvent__e` |
-| shouldSave | Boolean | Determines if the builder's instance of `LogEntryEvent__e` should be saved |
| isConsoleLoggingEnabled | Boolean | Determines if `console.log()` methods are execute |
@@ -32,7 +31,7 @@ This class is the JavaScript-equivalent of the Apex class `LogEntryBuilder`
Sets the log entry event's message field
-**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
+**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
**Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -45,7 +44,7 @@ Sets the log entry event's message field
Sets the log entry event's record fields
-**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
+**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
**Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -58,7 +57,7 @@ Sets the log entry event's record fields
Sets the log entry event's record fields
-**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
+**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
**Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -71,7 +70,7 @@ Sets the log entry event's record fields
Sets the log entry event's exception fields
-**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
+**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
**Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -84,7 +83,7 @@ Sets the log entry event's exception fields
Appends the tag to the existing list of tags
-**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
+**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
**Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -97,7 +96,7 @@ Appends the tag to the existing list of tags
Appends the tag to the existing list of tags
-**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
+**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder)
**Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods
| Param | Type | Description |
diff --git a/docs/lightning-components/Logger.md b/docs/lightning-components/Logger.md
index 7b38663e5..207d32ec3 100644
--- a/docs/lightning-components/Logger.md
+++ b/docs/lightning-components/Logger.md
@@ -1,12 +1,12 @@
## Functions
Sets the scenario name for the current transaction - this is stored in LogEntryEvent__e.Scenario__c
- and Log__c.TransactionScenario__c, and can be used to filter & group logs
+ and Log__c.Scenario__c, and can be used to filter & group logs
Saves any entries in Logger's buffer, using the specified save method for only this call.
- All subsequent calls to saveLog() will use the transaction save method.
+
Saves any entries in Logger's buffer, using the specified save method for only this call
+ All subsequent calls to saveLog() will use the transaction save method
-## getUserSettings() ComponentLogger.ComponentLoggerSettings
+## getUserSettings(parameters) Promise.<ComponentLogger.ComponentLoggerSettings>
-Returns information about the current user's settings, stored in `LoggerSettings__c`
+Returns **read-only** information about the current user's settings, stored in `LoggerSettings__c`
+
+**Kind**: global function
+**Returns**: Promise.<ComponentLogger.ComponentLoggerSettings> - The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings`
+
+| Param | Type | Description |
+| ---------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------ |
+| parameters | Object | Object used to provide control over how user settings are retrieved. Currently, only the property `forceReload` is used. |
-**Kind**: global function
-**Returns**: ComponentLogger.ComponentLoggerSettings - The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings`
-## setScenario(scenario)
+## setScenario(scenario) Array.<Promise>
Sets the scenario name for the current transaction - this is stored in `LogEntryEvent__e.Scenario__c`
and `Log__c.Scenario__c`, and can be used to filter & group logs
-**Kind**: global function
+**Kind**: global function
+**Returns**: Array.<Promise> - A list of promises that be resolved before all scenarios are set
| Param | Type | Description |
| -------- | ------------------- | ------------------------------------------------------ |
@@ -68,7 +76,7 @@ and `Log__c.Scenario__c`, and can be used to filter & group logs
Creates a new log entry with logging level == `LoggingLevel.ERROR`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -81,7 +89,7 @@ Creates a new log entry with logging level == `LoggingLevel.ERROR`
Creates a new log entry with logging level == `LoggingLevel.WARN`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -94,7 +102,7 @@ Creates a new log entry with logging level == `LoggingLevel.WARN`
Creates a new log entry with logging level == `LoggingLevel.INFO`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -107,7 +115,7 @@ Creates a new log entry with logging level == `LoggingLevel.INFO`
Creates a new log entry with logging level == `LoggingLevel.DEBUG`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -120,7 +128,7 @@ Creates a new log entry with logging level == `LoggingLevel.DEBUG`
Creates a new log entry with logging level == `LoggingLevel.FINE`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -133,7 +141,7 @@ Creates a new log entry with logging level == `LoggingLevel.FINE`
Creates a new log entry with logging level == `LoggingLevel.FINER`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -146,7 +154,7 @@ Creates a new log entry with logging level == `LoggingLevel.FINER`
Creates a new log entry with logging level == `LoggingLevel.FINEST`
-**Kind**: global function
+**Kind**: global function
**Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
| Param | Type | Description |
@@ -159,24 +167,32 @@ Creates a new log entry with logging level == `LoggingLevel.FINEST`
Returns the number of entries that have been generated but not yet saved
-**Kind**: global function
-**Returns**: Integer - The buffer's current size
+**Kind**: global function
+**Returns**: Integer - The buffer's current size
-## flushBuffer()
+## flushBuffer() Promise.<void>
Discards any entries that have been generated but not yet saved
-**Kind**: global function
+**Kind**: global function
+**Returns**: Promise.<void> - A promise to clear the entries
## saveLog(saveMethod)
-Saves any entries in Logger's buffer, using the specified save method for only this call.
-All subsequent calls to saveLog() will use the transaction save method.
+Saves any entries in Logger's buffer, using the specified save method for only this call
+All subsequent calls to saveLog() will use the transaction save method
**Kind**: global function
-| Param | Type | Description |
-| ---------- | ------------------- | ------------------------------------------------------------------------- |
-| saveMethod | String | The enum value of Logger.SaveMethod to use for this specific save action. |
+| Param | Type | Description |
+| ---------- | ------------------- | ------------------------------------------------------------------------ |
+| saveMethod | String | The enum value of Logger.SaveMethod to use for this specific save action |
+
+
+
+## createLogger() LoggerService
+
+**Kind**: global function
+**Returns**: LoggerService - a LoggerService instance
diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls
index 7a655c79f..32bf16b89 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.10.1';
+ private static final String CURRENT_VERSION_NUMBER = 'v4.10.2';
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/__tests__/logger.test.js b/nebula-logger/core/main/logger-engine/lwc/logger/__tests__/logger.test.js
index 187a3875e..14949ab82 100644
--- a/nebula-logger/core/main/logger-engine/lwc/logger/__tests__/logger.test.js
+++ b/nebula-logger/core/main/logger-engine/lwc/logger/__tests__/logger.test.js
@@ -1,155 +1,621 @@
import { createElement } from 'lwc';
+// Recommended approach
+import { createLogger } from 'c/logger';
+// Legacy approach
import Logger from 'c/logger';
import getSettings from '@salesforce/apex/ComponentLogger.getSettings';
const MOCK_GET_SETTINGS = require('./data/getLoggerSettings.json');
+const flushPromises = async () => {
+ await new Promise(process.nextTick);
+};
+
jest.mock(
'@salesforce/apex/ComponentLogger.getSettings',
() => {
- const { createApexTestWireAdapter } = require('@salesforce/sfdx-lwc-jest');
return {
- default: createApexTestWireAdapter(jest.fn())
+ default: jest.fn()
};
},
{ virtual: true }
);
-describe('Logger lwc tests', () => {
+describe('logger lwc import tests', () => {
+ afterEach(() => {
+ createLogger().flushBuffer();
+ jest.clearAllMocks();
+ });
+
+ it('returns user settings when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+
+ const userSettings = await logger.getUserSettings();
+
+ expect(userSettings.defaultSaveMethod).toEqual('EVENT_BUS');
+ expect(userSettings.isEnabled).toEqual(true);
+ expect(userSettings.isConsoleLoggingEnabled).toEqual(true);
+ });
+
+ it('sets a log scenario on all entries when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ await logger.getUserSettings();
+ const scenario = 'some scenario';
+ const message = 'some message';
+ const firstLogEntry = await logger.finest(message);
+ await flushPromises();
+ expect(firstLogEntry.scenario).toBeUndefined();
+ expect(logger.getBufferSize()).toEqual(1);
+ const secondLogEntry = logger.info(message);
+ await flushPromises();
+ expect(secondLogEntry.scenario).toBeUndefined();
+ expect(logger.getBufferSize()).toEqual(2);
+
+ await logger.setScenario(scenario);
+
+ expect(firstLogEntry.scenario).toEqual(scenario);
+ expect(secondLogEntry.scenario).toEqual(scenario);
+ });
+
+ it('logs an ERROR entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel ERROR';
+
+ const logEntry = logger.error(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('ERROR');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('logs a WARN entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel WARN';
+
+ const logEntry = logger.warn(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('WARN');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('logs an INFO entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel INFO';
+
+ const logEntry = logger.info(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('INFO');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('logs a DEBUG entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel DEBUG';
+
+ const logEntry = logger.debug(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('DEBUG');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('logs a FINE entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel FINE';
+
+ const logEntry = logger.fine(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('FINE');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('logs a FINER entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel FINER';
+
+ const logEntry = logger.finer(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('FINER');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('logs a FINEST entry when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const message = 'component log entry with loggingLevel FINEST';
+
+ const logEntry = logger.finest(message);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(1);
+ expect(logEntry.loggingLevel).toEqual('FINEST');
+ expect(logEntry.message).toEqual(message);
+ });
+
+ it('sets recordId when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ await logger.getUserSettings();
+ const logEntry = logger.info('example log entry');
+ expect(logEntry.recordId).toBeFalsy();
+ const mockUserId = '0052F000008yLcEQAU';
+
+ logEntry.setRecordId(mockUserId);
+
+ expect(logEntry.recordId).toEqual(mockUserId);
+ });
+
+ it('sets record when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ await logger.getUserSettings();
+ const logEntry = logger.info('example log entry');
+ expect(logEntry.record).toBeFalsy();
+ const mockUserRecord = { Id: '0052F000008yLcEQAU', FirstName: 'Jonathan', LastName: 'Gillespie' };
+
+ logEntry.setRecord(mockUserRecord);
+
+ expect(logEntry.record).toEqual(mockUserRecord);
+ });
+
+ it('sets JavaScript error details when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ await logger.getUserSettings();
+ const logEntry = logger.info('example log entry');
+ expect(logEntry.error).toBeFalsy();
+ const error = new TypeError('oops');
+ expect(error).toBeTruthy();
+ expect(error.message).toBeTruthy();
+ expect(error.stack).toBeTruthy();
+
+ logEntry.setError(error);
+
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.error.type).toEqual('JavaScript.TypeError');
+ });
+
+ it('sets Apex error details when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = logger.info('example log entry');
+ expect(logEntry.error).toBeFalsy();
+ const error = {
+ body: {
+ exceptionType: 'System.DmlException',
+ message: 'Some Apex error, oh no!',
+ stackTrace: 'Class.SomeApexClass.runSomeMethod: line 314, column 42'
+ }
+ };
+ expect(error).toBeTruthy();
+ expect(error.body.exceptionType).toBeTruthy();
+ expect(error.body.message).toBeTruthy();
+ expect(error.body.stackTrace).toBeTruthy();
+
+ logEntry.setError(error);
+
+ expect(logEntry.error.message).toEqual(error.body.message);
+ expect(logEntry.error.stack).toEqual(error.body.stackTrace);
+ expect(logEntry.error.type).toEqual(error.body.exceptionType);
+ });
+
+ it('adds tags when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = logger.info('example log entry');
+ expect(logEntry.recordId).toBeFalsy();
+ const mockTags = ['first tag', 'second tag', 'third tag'];
+
+ logEntry.addTags(mockTags);
+
+ expect(logEntry.tags.length).toEqual(mockTags.length);
+ });
+
+ it('deduplicates tags when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = logger.info('example log entry');
+ expect(logEntry.recordId).toBeFalsy();
+ const mockTags = ['duplicate tag', 'duplicate tag'];
+ expect(mockTags.length).toEqual(2);
+ expect(new Set(mockTags).size).toEqual(1);
+
+ for (let i = 0; i < mockTags.length; i++) {
+ logEntry.addTag(mockTags[i]);
+ }
+
+ expect(logEntry.tags.length).toEqual(1);
+ });
+
+ it('still works for ERROR logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .error('example ERROR log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('ERROR');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('still works for WARN logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .warn('example WARN log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('WARN');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('still works for INFO logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .info('example INFO log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('INFO');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('still works for DEBUG logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .debug('example DEBUG log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('DEBUG');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('still works for FINE logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .fine('example FINE log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('FINE');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('still works for FINER logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .finer('example FINER log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('FINER');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('still works for FINEST logging level when disabled when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
+
+ const logEntry = logger
+ .finest('example FINEST log entry')
+ .setMessage('some message')
+ .setRecordId('some_record_Id')
+ .setRecord({ Id: 'some_record_Id' })
+ .setError(error)
+ .addTag('a tag')
+ .addTags(['a second tag', 'a third tag']);
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(0);
+ expect(logEntry.loggingLevel).toEqual('FINEST');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
+ });
+
+ it('flushes buffer when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ await logger.getUserSettings({ forceReload: true });
+ const numberOfLogEntries = 3;
+ for (let i = 0; i < numberOfLogEntries; i++) {
+ logger.info('entry number: ' + i);
+ }
+ await flushPromises();
+ expect(logger.getBufferSize()).toEqual(numberOfLogEntries);
+
+ await logger.flushBuffer();
+
+ expect(logger.getBufferSize()).toEqual(0);
+ });
+
+ it('saves log entries and flushes buffer when using recommended import approach', async () => {
+ const logger = createLogger();
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ await logger.getUserSettings({ forceReload: true });
+ logger.info('example INFO log entry');
+ logger.debug('example DEBUG log entry');
+ await flushPromises();
+ expect(logger.getBufferSize()).toBe(2);
+
+ logger.saveLog();
+
+ await flushPromises();
+ expect(logger.getBufferSize()).toBe(0);
+ });
+});
+
+describe('logger lwc legacy markup tests', () => {
afterEach(() => {
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
+ createLogger().flushBuffer();
jest.clearAllMocks();
});
- it('returns user settings', async () => {
+ it('returns user settings when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
- const userSettings = logger.getUserSettings();
+ const userSettings = await logger.getUserSettings();
expect(userSettings.defaultSaveMethod).toEqual('EVENT_BUS');
expect(userSettings.isEnabled).toEqual(true);
expect(userSettings.isConsoleLoggingEnabled).toEqual(true);
});
- it('sets a log scenario on all entries', async () => {
+ it('sets a log scenario on all entries when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = true;
- const scenario = 'some scenario';
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'some message';
- const firstLogEntry = logger.finest(message);
+ const firstLogEntry = await logger.finest(message);
expect(firstLogEntry.scenario).toBeUndefined();
expect(logger.getBufferSize()).toEqual(1);
- const secondLogEntry = logger.info(message);
+ const secondLogEntry = await logger.info(message);
expect(secondLogEntry.scenario).toBeUndefined();
expect(logger.getBufferSize()).toEqual(2);
+ const scenario = 'some scenario';
logger.setScenario(scenario);
expect(firstLogEntry.scenario).toEqual(scenario);
expect(secondLogEntry.scenario).toEqual(scenario);
});
- it('logs an ERROR entry', async () => {
+ it('logs an ERROR entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel ERROR';
- const logEntry = logger.error(message);
+ const logEntry = await logger.error(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('ERROR');
expect(logEntry.message).toEqual(message);
});
- it('logs a WARN entry', async () => {
+ it('logs a WARN entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel WARN';
- const logEntry = logger.warn(message);
+ const logEntry = await logger.warn(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('WARN');
expect(logEntry.message).toEqual(message);
});
- it('logs an INFO entry', async () => {
+ it('logs an INFO entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel INFO';
- const logEntry = logger.info(message);
+ const logEntry = await logger.info(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('INFO');
expect(logEntry.message).toEqual(message);
});
- it('logs a DEBUG entry', async () => {
+ it('logs a DEBUG entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel DEBUG';
- const logEntry = logger.debug(message);
+ const logEntry = await logger.debug(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('DEBUG');
expect(logEntry.message).toEqual(message);
});
- it('logs a FINE entry', async () => {
+ it('logs a FINE entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel FINE';
- const logEntry = logger.fine(message);
+ const logEntry = await logger.fine(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('FINE');
expect(logEntry.message).toEqual(message);
});
- it('logs a FINER entry', async () => {
+ it('logs a FINER entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel FINER';
- const logEntry = logger.finer(message);
+ const logEntry = await logger.finer(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('FINER');
expect(logEntry.message).toEqual(message);
});
- it('logs a FINEST entry', async () => {
+ it('logs a FINEST entry when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const message = 'component log entry with loggingLevel FINEST';
- const logEntry = logger.finest(message);
+ const logEntry = await logger.finest(message);
expect(logger.getBufferSize()).toEqual(1);
expect(logEntry.loggingLevel).toEqual('FINEST');
expect(logEntry.message).toEqual(message);
});
- it('sets recordId', async () => {
+ it('sets recordId when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- const logEntry = logger.info('example log entry');
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = await logger.info('example log entry');
expect(logEntry.recordId).toBeFalsy();
const mockUserId = '0052F000008yLcEQAU';
@@ -158,11 +624,11 @@ describe('Logger lwc tests', () => {
expect(logEntry.recordId).toEqual(mockUserId);
});
- it('sets record', async () => {
+ it('sets record when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- const logEntry = logger.info('example log entry');
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = await logger.info('example log entry');
expect(logEntry.record).toBeFalsy();
const mockUserRecord = { Id: '0052F000008yLcEQAU', FirstName: 'Jonathan', LastName: 'Gillespie' };
@@ -171,11 +637,11 @@ describe('Logger lwc tests', () => {
expect(logEntry.record).toEqual(mockUserRecord);
});
- it('sets JavaScript error details', async () => {
+ it('sets JavaScript error details when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- const logEntry = logger.info('example log entry');
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = await logger.info('example log entry');
expect(logEntry.error).toBeFalsy();
const error = new TypeError('oops');
expect(error).toBeTruthy();
@@ -189,11 +655,11 @@ describe('Logger lwc tests', () => {
expect(logEntry.error.type).toEqual('JavaScript.TypeError');
});
- it('sets Apex error details', async () => {
+ it('sets Apex error details when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- const logEntry = logger.info('example log entry');
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = await logger.info('example log entry');
expect(logEntry.error).toBeFalsy();
const error = {
body: {
@@ -214,11 +680,11 @@ describe('Logger lwc tests', () => {
expect(logEntry.error.type).toEqual(error.body.exceptionType);
});
- it('adds tags', async () => {
+ it('adds tags when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- const logEntry = logger.info('example log entry');
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = await logger.info('example log entry');
expect(logEntry.recordId).toBeFalsy();
const mockTags = ['first tag', 'second tag', 'third tag'];
@@ -227,11 +693,11 @@ describe('Logger lwc tests', () => {
expect(logEntry.tags.length).toEqual(mockTags.length);
});
- it('deduplicates tags', async () => {
+ it('deduplicates tags when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- const logEntry = logger.info('example log entry');
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
+ const logEntry = await logger.info('example log entry');
expect(logEntry.recordId).toBeFalsy();
const mockTags = ['duplicate tag', 'duplicate tag'];
expect(mockTags.length).toEqual(2);
@@ -244,220 +710,243 @@ describe('Logger lwc tests', () => {
expect(logEntry.tags.length).toEqual(1);
});
- it('still works for ERROR logging level when disabled', async () => {
+ it('still works for ERROR logging level when disabled when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.error('example ERROR log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('ERROR');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('still works for WARN logging level when disabled', async () => {
+ it('still works for WARN logging level when disabled when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.warn('example WARN log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
expect(logger.getBufferSize()).toEqual(0);
- expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('WARN');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('still works for INFO logging level when disabled', async () => {
+ it('still works for INFO logging level when disabled when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.info('example INFO log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
expect(logger.getBufferSize()).toEqual(0);
- expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('INFO');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('still works for DEBUG logging level when disabled', async () => {
+ it('still works for DEBUG logging level when disabled when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.debug('example DEBUG log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
expect(logger.getBufferSize()).toEqual(0);
- expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('DEBUG');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('still works for FINE logging level when disabled', async () => {
+ it('still works for FINE logging level when disabled when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.fine('example FINE log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
expect(logger.getBufferSize()).toEqual(0);
- expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('FINE');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('still works for FINER logging level when disabled', async () => {
+ it('still works for FINER logging level when disabled when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: false });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.finer('example FINER log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
expect(logger.getBufferSize()).toEqual(0);
- expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('FINER');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('still works for FINEST logging level when disabled', async () => {
+ it('still works for FINEST logging level when disabled when using deprecated markup approach', async () => {
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
- logger.getUserSettings().isEnabled = false;
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS, isEnabled: true });
+ const settings = await logger.getUserSettings();
+ expect(settings.isEnabled).toEqual(false);
+ const error = new TypeError('oops');
const logEntry = logger
.finest('example FINEST log entry')
.setMessage('some message')
.setRecordId('some_record_Id')
.setRecord({ Id: 'some_record_Id' })
- .setError(new TypeError('oops'))
+ .setError(error)
.addTag('a tag')
.addTags(['a second tag', 'a third tag']);
+ await flushPromises();
expect(logger.getBufferSize()).toEqual(0);
- expect(logger.getBufferSize()).toEqual(0);
- expect(logEntry.loggingLevel).toEqual(undefined);
- expect(logEntry.shouldSave).toEqual(false);
- expect(logEntry.recordId).toEqual(undefined);
- expect(logEntry.record).toEqual(undefined);
- expect(logEntry.error).toEqual(undefined);
- expect(logEntry.stack).toEqual(undefined);
- expect(logEntry.timestamp).toEqual(undefined);
- expect(logEntry.tags).toEqual(undefined);
+ expect(logEntry.loggingLevel).toEqual('FINEST');
+ expect(logEntry.recordId).toEqual('some_record_Id');
+ expect(logEntry.record).toEqual({ Id: 'some_record_Id' });
+ expect(logEntry.error).toBeTruthy();
+ expect(logEntry.stack).toBeTruthy();
+ expect(logEntry.error.message).toEqual(error.message);
+ expect(logEntry.error.stack).toEqual(error.stack);
+ expect(logEntry.timestamp).toBeTruthy();
+ expect(logEntry.tags).toEqual(['a tag', 'a second tag', 'a third tag']);
});
- it('flushes buffer', async () => {
+ it('flushes buffer when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(true);
const numberOfLogEntries = 3;
for (let i = 0; i < numberOfLogEntries; i++) {
logger.info('entry number: ' + i);
}
+ await flushPromises();
expect(logger.getBufferSize()).toEqual(numberOfLogEntries);
- logger.flushBuffer();
+ await logger.flushBuffer();
+ await flushPromises();
expect(logger.getBufferSize()).toEqual(0);
});
- it('saves log entries and flushes buffer', async () => {
+ it('saves log entries and flushes buffer when using deprecated markup approach', async () => {
+ getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
const logger = createElement('c-logger', { is: Logger });
document.body.appendChild(logger);
- getSettings.emit({ ...MOCK_GET_SETTINGS });
+ const settings = await logger.getUserSettings({ forceReload: true });
+ expect(settings.isEnabled).toEqual(true);
logger.info('example INFO log entry');
logger.debug('example DEBUG log entry');
+ await flushPromises();
expect(logger.getBufferSize()).toBe(2);
logger.saveLog();
- await Promise.resolve();
+ await flushPromises();
expect(logger.getBufferSize()).toBe(0);
});
});
diff --git a/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js b/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js
index 0b3b54472..321cb876e 100644
--- a/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js
+++ b/nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js
@@ -4,22 +4,20 @@
//------------------------------------------------------------------------------------------------//
const LogEntryBuilder = class {
+ #settingsPromise;
+
/**
* @description Constructor used to generate each JavaScript-based log entry event
* This class is the JavaScript-equivalent of the Apex class `LogEntryBuilder`
* @param {String} loggingLevel The `LoggingLevel` enum to use for the builder's instance of `LogEntryEvent__e`
- * @param {Boolean} shouldSave Determines if the builder's instance of `LogEntryEvent__e` should be saved
* @param {Boolean} isConsoleLoggingEnabled Determines if `console.log()` methods are execute
*/
- constructor(loggingLevel, shouldSave, isConsoleLoggingEnabled) {
- this.shouldSave = shouldSave;
- this.isConsoleLoggingEnabled = isConsoleLoggingEnabled;
- if (this.shouldSave === true) {
- this.loggingLevel = loggingLevel;
- this.stack = new Error().stack;
- this.timestamp = new Date().toISOString();
- this.tags = [];
- }
+ constructor(loggingLevel, settingsPromise) {
+ this.#settingsPromise = settingsPromise;
+ this.loggingLevel = loggingLevel;
+ this.stack = new Error().stack;
+ this.timestamp = new Date().toISOString();
+ this.tags = [];
}
/**
@@ -28,10 +26,8 @@ const LogEntryBuilder = class {
* @return {LogEntryBuilder} The same instance of `LogEntryBuilder`, useful for chaining methods
*/
setMessage(message) {
- if (this.shouldSave === true) {
- this.message = message;
- this._logToConsole();
- }
+ this.message = message;
+ this._logToConsole();
return this;
}
@@ -41,9 +37,7 @@ const LogEntryBuilder = class {
* @return {LogEntryBuilder} The same instance of `LogEntryBuilder`, useful for chaining methods
*/
setRecordId(recordId) {
- if (this.shouldSave === true) {
- this.recordId = recordId;
- }
+ this.recordId = recordId;
return this;
}
@@ -53,9 +47,7 @@ const LogEntryBuilder = class {
* @return {LogEntryBuilder} The same instance of `LogEntryBuilder`, useful for chaining methods
*/
setRecord(record) {
- if (this.shouldSave === true) {
- this.record = record;
- }
+ this.record = record;
return this;
}
@@ -65,17 +57,15 @@ const LogEntryBuilder = class {
* @return {LogEntryBuilder} The same instance of `LogEntryBuilder`, useful for chaining methods
*/
setError(error) {
- if (this.shouldSave === true) {
- this.error = {};
- if (error.body) {
- this.error.message = error.body.message;
- this.error.stack = error.body.stackTrace;
- this.error.type = error.body.exceptionType;
- } else {
- this.error.message = error.message;
- this.error.stack = error.stack;
- this.error.type = 'JavaScript.' + error.name;
- }
+ this.error = {};
+ if (error.body) {
+ this.error.message = error.body.message;
+ this.error.stack = error.body.stackTrace;
+ this.error.type = error.body.exceptionType;
+ } else {
+ this.error.message = error.message;
+ this.error.stack = error.stack;
+ this.error.type = 'JavaScript.' + error.name;
}
return this;
}
@@ -86,11 +76,9 @@ const LogEntryBuilder = class {
* @return {LogEntryBuilder} The same instance of `LogEntryBuilder`, useful for chaining methods
*/
addTag(tag) {
- if (this.shouldSave === true) {
- this.tags.push(tag);
- // Deduplicate the list of tags
- this.tags = Array.from(new Set(this.tags));
- }
+ this.tags.push(tag);
+ // Deduplicate the list of tags
+ this.tags = Array.from(new Set(this.tags));
return this;
}
@@ -107,28 +95,42 @@ const LogEntryBuilder = class {
}
_logToConsole() {
- if (!this.isConsoleLoggingEnabled) {
- return;
- }
+ this.#settingsPromise().then(setting => {
+ this.isConsoleLoggingEnabled = setting.isConsoleLoggingEnabled;
- /* eslint-disable no-console */
- switch (this.loggingLevel) {
- case 'ERROR':
- console.error(this.message, this);
- break;
- case 'WARN':
- console.warn(this.message, this);
- break;
- case 'INFO':
- console.info(this.message, this);
- break;
- default:
- console.debug(this.message, this);
- break;
- }
+ if (!this.isConsoleLoggingEnabled) {
+ return;
+ }
+
+ const consoleMessagePrefix = '%c Nebula Logger ';
+ const consoleFormatting = 'background: #0c598d; color: #fff; font-size: 12px; font-weight:bold;';
+ let consoleLoggingFunction;
+ switch (this.loggingLevel) {
+ case 'ERROR':
+ consoleLoggingFunction = console.error;
+ break;
+ case 'WARN':
+ consoleLoggingFunction = console.warn;
+ break;
+ case 'INFO':
+ consoleLoggingFunction = console.info;
+ break;
+ default:
+ consoleLoggingFunction = console.debug;
+ break;
+ }
+
+ consoleLoggingFunction(consoleMessagePrefix, consoleFormatting, this.message);
+ console.groupCollapsed(consoleMessagePrefix, consoleFormatting, 'Details for: ' + this.message);
+ // The use of JSON.parse(JSON.stringify()) is intended to help ensure that the output is readable,
+ // including handling proxy objects. If any cyclic objects are used, this approach could fail
+ consoleLoggingFunction(JSON.parse(JSON.stringify(this)));
+ console.trace();
+ console.groupEnd();
+ });
}
};
-export function newLogEntry(loggingLevel, shouldSave, isConsoleLoggingEnabled) {
- return new LogEntryBuilder(loggingLevel, shouldSave, isConsoleLoggingEnabled);
+export function newLogEntry(loggingLevel, settingPromise) {
+ return new LogEntryBuilder(loggingLevel, settingPromise);
}
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 369b072d8..1e40aca28 100644
--- a/nebula-logger/core/main/logger-engine/lwc/logger/logger.js
+++ b/nebula-logger/core/main/logger-engine/lwc/logger/logger.js
@@ -3,47 +3,33 @@
// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. //
//------------------------------------------------------------------------------------------------//
-import { LightningElement, api, wire } from 'lwc';
-import { newLogEntry } from './logEntryBuilder';
-import getSettings from '@salesforce/apex/ComponentLogger.getSettings';
-import saveComponentLogEntries from '@salesforce/apex/ComponentLogger.saveComponentLogEntries';
+import { LightningElement, api } from 'lwc';
+import { createLoggerService } from './loggerService';
+
+const CURRENT_VERSION_NUMBER = 'v4.10.2';
export default class Logger extends LightningElement {
- componentLogEntries = [];
- settings;
-
- _scenario;
-
- @wire(getSettings)
- wiredSettings({ error, data }) {
- if (data) {
- this.settings = data;
- } else if (error) {
- /* eslint-disable-next-line no-console */
- console.error(error);
- }
- }
+ #loggerService = createLoggerService();
/**
- * @description Returns information about the current user's settings, stored in `LoggerSettings__c`
- * @return {ComponentLogger.ComponentLoggerSettings} The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings`
+ * @description Returns **read-only** information about the current user's settings, stored in `LoggerSettings__c`
+ * @param {Object} parameters Object used to provide control over how user settings are retrieved. Currently, only the property `forceReload` is used.
+ * @return {Promise} The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings`
*/
@api
- getUserSettings() {
- return this.settings;
+ getUserSettings(parameters = { forceReload: false }) {
+ return this.#loggerService.getUserSettings(parameters);
}
/**
* @description Sets the scenario name for the current transaction - this is stored in `LogEntryEvent__e.Scenario__c`
* and `Log__c.Scenario__c`, and can be used to filter & group logs
* @param {String} scenario The name to use for the current transaction's scenario
+ * @return {Promise[]} A list of promises that be resolved before all scenarios are set
*/
@api
setScenario(scenario) {
- this._scenario = scenario;
- this.componentLogEntries.forEach(logEntry => {
- logEntry.scenario = this._scenario;
- });
+ return this.#loggerService.setScenario(scenario);
}
/**
@@ -53,7 +39,7 @@ export default class Logger extends LightningElement {
*/
@api
error(message) {
- return this._newEntry('ERROR', message);
+ return this.#loggerService.error(message);
}
/**
@@ -63,7 +49,7 @@ export default class Logger extends LightningElement {
*/
@api
warn(message) {
- return this._newEntry('WARN', message);
+ return this.#loggerService.warn(message);
}
/**
@@ -73,7 +59,7 @@ export default class Logger extends LightningElement {
*/
@api
info(message) {
- return this._newEntry('INFO', message);
+ return this.#loggerService.info(message);
}
/**
@@ -83,7 +69,7 @@ export default class Logger extends LightningElement {
*/
@api
debug(message) {
- return this._newEntry('DEBUG', message);
+ return this.#loggerService.debug(message);
}
/**
@@ -93,7 +79,7 @@ export default class Logger extends LightningElement {
*/
@api
fine(message) {
- return this._newEntry('FINE', message);
+ return this.#loggerService.fine(message);
}
/**
@@ -103,7 +89,7 @@ export default class Logger extends LightningElement {
*/
@api
finer(message) {
- return this._newEntry('FINER', message);
+ return this.#loggerService.finer(message);
}
/**
@@ -113,7 +99,7 @@ export default class Logger extends LightningElement {
*/
@api
finest(message) {
- return this._newEntry('FINEST', message);
+ return this.#loggerService.finest(message);
}
/**
@@ -122,58 +108,37 @@ export default class Logger extends LightningElement {
*/
@api
getBufferSize() {
- return this.componentLogEntries.length;
+ return this.#loggerService.getBufferSize();
}
/**
* @description Discards any entries that have been generated but not yet saved
+ * @return {Promise} A promise to clear the entries
*/
@api
flushBuffer() {
- this.componentLogEntries = [];
+ return this.#loggerService.flushBuffer();
}
/**
- * @description Saves any entries in Logger's buffer, using the specified save method for only this call.
- * All subsequent calls to saveLog() will use the transaction save method.
- * @param {String} saveMethod The enum value of Logger.SaveMethod to use for this specific save action.
+ * @description Saves any entries in Logger's buffer, using the specified save method for only this call
+ * All subsequent calls to saveLog() will use the transaction save method
+ * @param {String} saveMethod The enum value of Logger.SaveMethod to use for this specific save action
*/
@api
saveLog(saveMethodName) {
- if (this.getBufferSize() > 0) {
- if (!saveMethodName && this.settings && this.settings.defaultSaveMethodName) {
- saveMethodName = this.settings.defaultSaveMethodName;
- }
-
- saveComponentLogEntries({ componentLogEntries: this.componentLogEntries, saveMethodName: saveMethodName })
- .then(this.flushBuffer())
- .catch(error => {
- if (this.settings.isConsoleLoggingEnabled === true) {
- /* eslint-disable-next-line no-console */
- console.error(error);
- /* eslint-disable-next-line no-console */
- console.error(this.componentLogEntries);
- }
- });
- }
- }
-
- // Private functions
- _meetsUserLoggingLevel(logEntryLoggingLevel) {
- let logEntryLoggingLevelOrdinal = this.settings.supportedLoggingLevels[logEntryLoggingLevel];
- return this.settings && this.settings.isEnabled === true && this.settings.userLoggingLevel.ordinal <= logEntryLoggingLevelOrdinal;
- }
-
- _newEntry(loggingLevel, message) {
- const shouldSave = this._meetsUserLoggingLevel(loggingLevel);
- const logEntryBuilder = newLogEntry(loggingLevel, shouldSave, this.settings.isConsoleLoggingEnabled).setMessage(message);
- if (this._scenario) {
- logEntryBuilder.scenario = this._scenario;
- }
- if (this._meetsUserLoggingLevel(loggingLevel) === true) {
- this.componentLogEntries.push(logEntryBuilder);
- }
-
- return logEntryBuilder;
+ this.#loggerService.saveLog(saveMethodName);
}
}
+
+/**
+ * @return {LoggerService} a LoggerService instance
+ */
+const createLogger = function () {
+ const consoleMessagePrefix = '%c Nebula Logger ';
+ const consoleFormatting = 'background: #0c598d; color: #fff;';
+ console.info(consoleMessagePrefix, consoleFormatting, 'Nebula Logger Version Number: ' + CURRENT_VERSION_NUMBER);
+ return createLoggerService();
+};
+
+export { createLogger };
diff --git a/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js b/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js
new file mode 100644
index 000000000..616924664
--- /dev/null
+++ b/nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js
@@ -0,0 +1,211 @@
+//------------------------------------------------------------------------------------------------//
+// 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 { newLogEntry } from './logEntryBuilder';
+import getSettings from '@salesforce/apex/ComponentLogger.getSettings';
+import saveComponentLogEntries from '@salesforce/apex/ComponentLogger.saveComponentLogEntries';
+
+const LoggerService = class {
+ static settings = undefined;
+
+ #componentLogEntries = [];
+ #scenario;
+
+ /**
+ * @description Queue of promises to be logged.
+ */
+ #loggingPromises = [];
+
+ /**
+ * @description Returns **read-only** information about the current user's settings, stored in `LoggerSettings__c`
+ * @param {Object} parameters Object used to provide control over how user settings are retrieved. Currently, only the property `forceReload` is used.
+ * @return {Promise} The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings`
+ */
+ getUserSettings({ forceReload = false } = {}) {
+ return this._loadSettingsFromServer(forceReload).then(existingSettings => {
+ return Object.freeze({
+ ...existingSettings,
+ supportedLoggingLevels: Object.freeze(existingSettings.supportedLoggingLevels),
+ userLoggingLevel: Object.freeze(existingSettings.userLoggingLevel)
+ });
+ });
+ }
+
+ /**
+ * @description Sets the scenario name for the current transaction - this is stored in `LogEntryEvent__e.Scenario__c`
+ * and `Log__c.Scenario__c`, and can be used to filter & group logs
+ * @param {String} scenario The name to use for the current transaction's scenario
+ * @return {Promise[]} A list of promises that be resolved before all scenarios are set
+ */
+ setScenario(scenario) {
+ this.#scenario = scenario;
+ return Promise.all(this.#loggingPromises).then(
+ this.#componentLogEntries.forEach(logEntry => {
+ logEntry.scenario = this.#scenario;
+ })
+ );
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.ERROR`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ error(message) {
+ return this._newEntry('ERROR', message);
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.WARN`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ warn(message) {
+ return this._newEntry('WARN', message);
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.INFO`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ info(message) {
+ return this._newEntry('INFO', message);
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.DEBUG`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ debug(message) {
+ return this._newEntry('DEBUG', message);
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.FINE`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ fine(message) {
+ return this._newEntry('FINE', message);
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.FINER`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ finer(message) {
+ return this._newEntry('FINER', message);
+ }
+
+ /**
+ * @description Creates a new log entry with logging level == `LoggingLevel.FINEST`
+ * @param {String} message The string to use to set the entry's message field
+ * @return {LogEntryBuilder} The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods
+ */
+ finest(message) {
+ return this._newEntry('FINEST', message);
+ }
+
+ /**
+ * @description Returns the number of entries that have been generated but not yet saved
+ * @return {Integer} The buffer's current size
+ */
+ getBufferSize() {
+ return this.#componentLogEntries.length;
+ }
+
+ /**
+ * @description Discards any entries that have been generated but not yet saved
+ * @return {Promise} A promise to clear the entries
+ */
+ flushBuffer() {
+ return Promise.all(this.#loggingPromises).then(() => {
+ this.#componentLogEntries = [];
+ this.#loggingPromises = [];
+ });
+ }
+
+ /**
+ * @description Saves any entries in Logger's buffer, using the specified save method for only this call
+ * All subsequent calls to saveLog() will use the transaction save method
+ * @param {String} saveMethod The enum value of LoggerService.SaveMethod to use for this specific save action
+ */
+ saveLog(saveMethodName) {
+ if (this.getBufferSize() > 0) {
+ let resolvedSaveMethodName;
+ if (!saveMethodName && LoggerService.settings && LoggerService.settings.defaultSaveMethodName) {
+ resolvedSaveMethodName = LoggerService.settings.defaultSaveMethodName;
+ } else {
+ resolvedSaveMethodName = saveMethodName;
+ }
+
+ Promise.all(this.#loggingPromises)
+ .then(saveComponentLogEntries({ componentLogEntries: this.#componentLogEntries, saveMethodName: resolvedSaveMethodName }))
+ .then(this.flushBuffer())
+ .catch(error => {
+ if (LoggerService.settings.isConsoleLoggingEnabled === true) {
+ /* eslint-disable-next-line no-console */
+ console.error(error);
+ /* eslint-disable-next-line no-console */
+ console.error(this.#componentLogEntries);
+ }
+ });
+ }
+ }
+
+ _loadSettingsFromServer(forceReload) {
+ // Loading only once
+ return LoggerService.settings === undefined || forceReload === true
+ ? getSettings()
+ .then(settings => {
+ LoggerService.settings = settings;
+ return settings;
+ })
+ .catch(error => {
+ /* eslint-disable-next-line no-console */
+ console.error(error);
+ })
+ : new Promise(resolve => {
+ resolve(LoggerService.settings);
+ });
+ }
+
+ _meetsUserLoggingLevel(logEntryLoggingLevel) {
+ let logEntryLoggingLevelOrdinal = LoggerService.settings.supportedLoggingLevels[logEntryLoggingLevel];
+ return (
+ LoggerService.settings &&
+ LoggerService.settings.isEnabled === true &&
+ LoggerService.settings.userLoggingLevel.ordinal <= logEntryLoggingLevelOrdinal
+ );
+ }
+
+ _newEntry(loggingLevel, message) {
+ // Builder is returned immediately but console log will be determined after loadding settings from server
+ const logEntryBuilder = newLogEntry(loggingLevel, this._loadSettingsFromServer);
+ logEntryBuilder.setMessage(message);
+ if (this.#scenario) {
+ logEntryBuilder.scenario = this.#scenario;
+ }
+ const loggingPromise = this._loadSettingsFromServer().then(() => {
+ if (this._meetsUserLoggingLevel(loggingLevel) === true) {
+ this.#componentLogEntries.push(logEntryBuilder);
+ }
+ });
+ this.#loggingPromises.push(loggingPromise);
+ return logEntryBuilder;
+ }
+};
+
+/**
+ * @return {LoggerService} a LoggerService instance
+ */
+const createLoggerService = function () {
+ return new LoggerService();
+};
+
+export { createLoggerService };
diff --git a/nebula-logger/recipes/applications/LoggerRecipes.app-meta.xml b/nebula-logger/recipes/applications/LoggerRecipes.app-meta.xml
index 6e493457a..6b7fdbe56 100644
--- a/nebula-logger/recipes/applications/LoggerRecipes.app-meta.xml
+++ b/nebula-logger/recipes/applications/LoggerRecipes.app-meta.xml
@@ -13,6 +13,7 @@
StandardLogger_lwc_demo
+ Logger_lwc_legacy_demoLoggerAuraDemoLightningLogger_Recipes_UtilityBar
diff --git a/nebula-logger/recipes/classes/LoggerLWCDemoController.cls b/nebula-logger/recipes/classes/LoggerLWCDemoController.cls
index 3099ad281..9cc7c0db0 100644
--- a/nebula-logger/recipes/classes/LoggerLWCDemoController.cls
+++ b/nebula-logger/recipes/classes/LoggerLWCDemoController.cls
@@ -1,5 +1,11 @@
@SuppressWarnings('PMD.ApexDoc')
public with sharing class LoggerLWCDemoController {
+ @AuraEnabled(cacheable=true)
+ public static String returnSomeString() {
+ System.debug('hello, world!');
+ return 'SomeString';
+ }
+
@AuraEnabled
public static void throwSomeError() {
throw new System.DmlException('Some Error!!');
diff --git a/nebula-logger/recipes/lwc/loggerLWCDemo/loggerLWCDemo.html b/nebula-logger/recipes/lwc/loggerLWCDemo/loggerLWCDemo.html
index 2928f9222..2d6d1aa70 100644
--- a/nebula-logger/recipes/lwc/loggerLWCDemo/loggerLWCDemo.html
+++ b/nebula-logger/recipes/lwc/loggerLWCDemo/loggerLWCDemo.html
@@ -6,9 +6,11 @@
-->
-
-
-
+
+
+ ✅ This component demonstrates how to use Nebula Logger by using import { createLogger } from 'c/logger'; in your component's
+ JavaScript file. This approach was introduced in Nebula Logger v4.10.2, and is now the recommended approach.
+
+ ⚠ This component demonstrates how to use Nebula Logger by adding <c-logger> to your component's markup. This approach is still
+ supported, but is considered deprecate as of v4.10.2. The new recommended approach is import the logger component in your component's JavaScript
+ file.
+