Skip to content

Commit b140e72

Browse files
authored
Properly handle logs created and saved through createLogger*( in pre-mounted instances (#577)
* Fixed #518 by calling saveLog() as soon as createLogger() has finished loading for pending log messages
1 parent 77fe275 commit b140e72

9 files changed

Lines changed: 121 additions & 31 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.
77

8-
## Unlocked Package - v4.11.11
8+
## Unlocked Package - v4.11.12
99

10-
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Oih7QAC)
11-
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Oih7QAC)
10+
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mjx5QAC)
11+
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001Mjx5QAC)
1212
[![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/)
1313

14-
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001Oih7QAC`
14+
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y000001Mjx5QAC`
1515

16-
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001Oih7QAC`
16+
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y000001Mjx5QAC`
1717

1818
---
1919

nebula-logger/core/main/logger-engine/classes/Logger.cls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
global with sharing class Logger {
1616
// There's no reliable way to get the version number dynamically in Apex
1717
@TestVisible
18-
private static final String CURRENT_VERSION_NUMBER = 'v4.11.11';
18+
private static final String CURRENT_VERSION_NUMBER = 'v4.11.12';
1919
private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG;
2020
private static final Set<String> IGNORED_APEX_CLASSES = initializeIgnoredApexClasses();
2121
private static final List<LogEntryEventBuilder> LOG_ENTRIES_BUFFER = new List<LogEntryEventBuilder>();

nebula-logger/core/main/logger-engine/lwc/logger/logEntryBuilder.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const ComponentLogEntry = class {
2727
}
2828
};
2929

30+
/* eslint-disable @lwc/lwc/no-dupe-class-members */
3031
const LogEntryBuilder = class {
3132
#componentLogEntry;
3233
#settingsPromise;
@@ -138,7 +139,7 @@ const LogEntryBuilder = class {
138139
/* eslint-disable no-console */
139140
_logToConsole() {
140141
this.#settingsPromise().then(setting => {
141-
this.isConsoleLoggingEnabled = setting.isConsoleLoggingEnabled;
142+
this.isConsoleLoggingEnabled = !!setting?.isConsoleLoggingEnabled;
142143

143144
if (!this.isConsoleLoggingEnabled) {
144145
return;

nebula-logger/core/main/logger-engine/lwc/logger/logger.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { LightningElement, api } from 'lwc';
77
import { createLoggerService } from './loggerService';
88

9-
const CURRENT_VERSION_NUMBER = 'v4.11.11';
9+
const CURRENT_VERSION_NUMBER = 'v4.11.12';
1010

1111
export default class Logger extends LightningElement {
1212
#loggerService = createLoggerService();

nebula-logger/core/main/logger-engine/lwc/logger/loggerService.js

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,17 @@ import { newLogEntry } from './logEntryBuilder';
77
import getSettings from '@salesforce/apex/ComponentLogger.getSettings';
88
import saveComponentLogEntries from '@salesforce/apex/ComponentLogger.saveComponentLogEntries';
99

10+
const LOADING_ENUM = {
11+
loading: 'loading',
12+
enabled: 'enabled',
13+
disabled: 'disabled'
14+
};
15+
1016
/* eslint-disable @lwc/lwc/no-dupe-class-members */
1117
const LoggerService = class {
1218
static settings = undefined;
1319

20+
#isSavingLog = false;
1421
#componentLogEntries = [];
1522
#scenario;
1623
#loggingPromises = [];
@@ -113,17 +120,18 @@ const LoggerService = class {
113120
* @return {Integer} The buffer's current size
114121
*/
115122
getBufferSize() {
116-
return this.#componentLogEntries.length;
123+
return this.#componentLogEntries.length + this.#loggingPromises.length;
117124
}
118125

119126
/**
120127
* @description Discards any entries that have been generated but not yet saved
121128
* @return {Promise<void>} A promise to clear the entries
122129
*/
123-
flushBuffer() {
130+
async flushBuffer() {
124131
return Promise.all(this.#loggingPromises).then(() => {
125132
this.#componentLogEntries = [];
126133
this.#loggingPromises = [];
134+
this.#isSavingLog = false;
127135
});
128136
}
129137

@@ -132,17 +140,31 @@ const LoggerService = class {
132140
* All subsequent calls to saveLog() will use the transaction save method
133141
* @param {String} saveMethod The enum value of LoggerService.SaveMethod to use for this specific save action
134142
*/
135-
saveLog(saveMethodName) {
136-
if (this.getBufferSize() > 0) {
143+
async saveLog(saveMethodName) {
144+
this.#isSavingLog = true;
145+
146+
const filteredLogEntries = this.#componentLogEntries.filter(
147+
possibleLogEntry =>
148+
(possibleLogEntry.loadingEnum === LOADING_ENUM.loading &&
149+
this._meetsUserLoggingLevel(possibleLogEntry.loggingLevel) === LOADING_ENUM.enabled) ||
150+
possibleLogEntry.loadingEnum === LOADING_ENUM.enabled
151+
);
152+
153+
if (filteredLogEntries.length > 0) {
137154
let resolvedSaveMethodName;
138155
if (!saveMethodName && LoggerService.settings && LoggerService.settings.defaultSaveMethodName) {
139156
resolvedSaveMethodName = LoggerService.settings.defaultSaveMethodName;
140157
} else {
141158
resolvedSaveMethodName = saveMethodName;
142159
}
143160

144-
Promise.all(this.#loggingPromises)
145-
.then(saveComponentLogEntries({ componentLogEntries: this.#componentLogEntries, saveMethodName: resolvedSaveMethodName }))
161+
return Promise.all(this.#loggingPromises)
162+
.then(
163+
saveComponentLogEntries({
164+
componentLogEntries: filteredLogEntries,
165+
saveMethodName: resolvedSaveMethodName
166+
})
167+
)
146168
.then(this.flushBuffer())
147169
.catch(error => {
148170
if (LoggerService.settings.isConsoleLoggingEnabled === true) {
@@ -153,6 +175,7 @@ const LoggerService = class {
153175
}
154176
});
155177
}
178+
return Promise.resolve();
156179
}
157180

158181
_loadSettingsFromServer(forceReload) {
@@ -173,27 +196,36 @@ const LoggerService = class {
173196
}
174197

175198
_meetsUserLoggingLevel(logEntryLoggingLevel) {
176-
let logEntryLoggingLevelOrdinal = LoggerService.settings.supportedLoggingLevels[logEntryLoggingLevel];
177-
return (
178-
LoggerService.settings &&
179-
LoggerService.settings.isEnabled === true &&
180-
LoggerService.settings.userLoggingLevel.ordinal <= logEntryLoggingLevelOrdinal
181-
);
199+
if (LoggerService.settings && LoggerService.settings.supportedLoggingLevels && LoggerService.settings.userLoggingLevel) {
200+
const currentIsEnabled =
201+
LoggerService.settings.isEnabled === true &&
202+
LoggerService.settings.userLoggingLevel.ordinal <= LoggerService.settings?.supportedLoggingLevels[logEntryLoggingLevel];
203+
return currentIsEnabled ? LOADING_ENUM.enabled : LOADING_ENUM.disabled;
204+
}
205+
return LOADING_ENUM.loading;
182206
}
183207

184208
_newEntry(loggingLevel, message) {
185-
// Builder is returned immediately but console log will be determined after loadding settings from server
209+
// Builder is returned immediately but console log will be determined after loading settings from server
186210
const logEntryBuilder = newLogEntry(loggingLevel, this._loadSettingsFromServer);
187211
logEntryBuilder.setMessage(message);
188212
if (this.#scenario) {
189213
logEntryBuilder.scenario = this.#scenario;
190214
}
191215
const loggingPromise = this._loadSettingsFromServer().then(() => {
192-
if (this._meetsUserLoggingLevel(loggingLevel) === true) {
193-
this.#componentLogEntries.push(logEntryBuilder.getComponentLogEntry());
216+
const isEnabledEnum = this._meetsUserLoggingLevel(loggingLevel);
217+
if (isEnabledEnum === LOADING_ENUM.enabled || isEnabledEnum === LOADING_ENUM.loading) {
218+
const componentLogEntry = logEntryBuilder.getComponentLogEntry();
219+
componentLogEntry.loadingEnum = isEnabledEnum;
220+
this.#componentLogEntries.push(componentLogEntry);
221+
}
222+
if (this.#isSavingLog) {
223+
this.#isSavingLog = false;
224+
this.saveLog();
194225
}
195226
});
196227
this.#loggingPromises.push(loggingPromise);
228+
197229
return logEntryBuilder;
198230
}
199231
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { createElement } from 'lwc';
2+
import LoggerLWCDemo from 'c/loggerLWCDemo';
3+
4+
import getSettings from '@salesforce/apex/ComponentLogger.getSettings';
5+
6+
const flushPromises = async () => {
7+
await new Promise(process.nextTick);
8+
};
9+
10+
const MOCK_GET_SETTINGS = {
11+
defaultSaveMethod: 'EVENT_BUS',
12+
isEnabled: true,
13+
isConsoleLoggingEnabled: true,
14+
supportedLoggingLevels: { FINEST: 2, FINER: 3, FINE: 4, DEBUG: 5, INFO: 6, WARN: 7, ERROR: 8 },
15+
userLoggingLevel: { ordinal: 2, name: 'FINEST' }
16+
};
17+
18+
jest.mock(
19+
'@salesforce/apex/ComponentLogger.getSettings',
20+
() => {
21+
return {
22+
default: jest.fn()
23+
};
24+
},
25+
{ virtual: true }
26+
);
27+
28+
describe('logger demo tests', () => {
29+
afterEach(() => {
30+
while (document.body.firstChild) {
31+
document.body.removeChild(document.body.firstChild);
32+
}
33+
jest.clearAllMocks();
34+
});
35+
36+
it('mounts and saves log correctly in one go', async () => {
37+
getSettings.mockResolvedValue({ ...MOCK_GET_SETTINGS });
38+
const demo = createElement('c-logger-demo', { is: LoggerLWCDemo });
39+
document.body.appendChild(demo);
40+
41+
await flushPromises();
42+
43+
expect(demo.logger?.getBufferSize()).toBe(0);
44+
});
45+
});

nebula-logger/recipes/lwc/loggerLWCDemo/loggerLWCDemo.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,21 @@ export default class LoggerLWCDemo extends LightningElement {
2626

2727
connectedCallback() {
2828
console.log('>>> start of connectedCallback()');
29-
this.logger.info('>>> running connectedCallback(), using createLogger()');
30-
this.logger.info('>>> adding an extra log entry');
31-
this.logger.saveLog();
32-
console.log('>>> done with connectedCallback()');
29+
try {
30+
this.logger.error('test error entry');
31+
this.logger.warn('test warn entry');
32+
this.logger.info('test info entry');
33+
this.logger.debug('test debug entry');
34+
this.logger.fine('test fine entry');
35+
this.logger.finer('test finer entry');
36+
this.logger.finest('test finest entry');
37+
throw new Error('A bad thing happened here');
38+
} catch (error) {
39+
this.logger.error('>>> connectedCallback error: ' + JSON.stringify(error));
40+
this.logger.saveLog().then(() => {
41+
console.log('done with async save');
42+
});
43+
}
3344
}
3445

3546
disconnectedCallback() {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nebula-logger",
3-
"version": "4.11.11",
3+
"version": "4.11.12",
44
"description": "The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.",
55
"author": "Jonathan Gillespie",
66
"license": "MIT",

sfdx-project.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
"package": "Nebula Logger - Core",
1414
"path": "./nebula-logger/core",
1515
"definitionFile": "./config/scratch-orgs/base-scratch-def.json",
16-
"versionNumber": "4.11.11.NEXT",
17-
"versionName": "Reduced Usage of Email Limits Consumption in LoggerEmailSender",
18-
"versionDescription": "Updated LoggerEmailSender to use the instance method Messaging.SingleEmailMessage.setTargetObjectId() when sending failure emails to internal users, which does not count towards the transactional email limits",
16+
"versionNumber": "4.11.12.NEXT",
17+
"versionName": "Bugfix for Lightning Component Entries Not Always Saving",
18+
"versionDescription": "Fixed an issue in the logger LWC where log entries in lightning components would be lost while trying to load LoggerSettings__c for the current user",
1919
"releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases",
2020
"unpackagedMetadata": {
2121
"path": "./nebula-logger/extra-tests"
@@ -159,6 +159,7 @@
159159
"Nebula Logger - Core@4.11.9-new-fields-log__c.loggedbyusernametext__c-and-logentry__c.loggedbyusernametext__c": "04t5Y000001OigJQAS",
160160
"Nebula Logger - Core@4.11.10-conditional-visibility-for-http-response-headers": "04t5Y000001OigxQAC",
161161
"Nebula Logger - Core@4.11.11-reduced-usage-of-email-limits-consumption-in-loggeremailsender": "04t5Y000001Oih7QAC",
162+
"Nebula Logger - Core@4.11.12-bugfix-for-lightning-component-entries-not-always-saving": "04t5Y000001Mjx5QAC",
162163
"Nebula Logger - Core Plugin - Async Failure Additions": "0Ho5Y000000blO4SAI",
163164
"Nebula Logger - Core Plugin - Async Failure Additions@1.0.0": "04t5Y0000015lhiQAA",
164165
"Nebula Logger - Core Plugin - Async Failure Additions@1.0.1": "04t5Y0000015lhsQAA",

0 commit comments

Comments
 (0)