From ebe7fb14b6aaa64a5e99e5ac0ae3250e09722a89 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Thu, 9 Nov 2023 20:12:05 -0600 Subject: [PATCH 1/3] feat: Add silent logLevels for Cloud Code --- spec/CloudCodeLogger.spec.js | 50 +++++++++++++++++++++++++++++ src/Controllers/LoggerController.js | 2 +- src/Routers/FunctionsRouter.js | 45 ++++++++++++++------------ src/triggers.js | 9 ++++++ 4 files changed, 85 insertions(+), 21 deletions(-) diff --git a/spec/CloudCodeLogger.spec.js b/spec/CloudCodeLogger.spec.js index b4dd5a42d8..4a22963bfd 100644 --- a/spec/CloudCodeLogger.spec.js +++ b/spec/CloudCodeLogger.spec.js @@ -334,4 +334,54 @@ describe('Cloud Code Logger', () => { expect(args[0]).toBe('Parse error: '); expect(args[1].message).toBe('Object not found.'); }); + + it('should log cloud function execution using the silent log level', async () => { + await reconfigureServer({ + silent: true, + logLevels: { + cloudFunctionSuccess: 'silent', + cloudFunctionError: 'silent', + }, + }); + Parse.Cloud.define('aFunction', () => { + return 'it worked!'; + }); + Parse.Cloud.define('bFunction', () => { + throw new Error('Failed'); + }); + spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough(); + + await Parse.Cloud.run('aFunction', { foo: 'bar' }); + expect(spy).toHaveBeenCalledTimes(0); + + await expectAsync(Parse.Cloud.run('bFunction', { foo: 'bar' })).toBeRejected(); + // Not "Failed running cloud function message..." + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should log cloud function triggers using the silent log level', async () => { + await reconfigureServer({ + logLevels: { + triggerAfter: 'silent', + triggerBeforeSuccess: 'silent', + triggerBeforeError: 'silent', + }, + }); + Parse.Cloud.beforeSave('TestClassError', () => { + throw new Error('Failed'); + }); + Parse.Cloud.beforeSave('TestClass', () => {}); + Parse.Cloud.afterSave('TestClass', () => {}); + + spy = spyOn(Config.get('test').loggerController.adapter, 'log').and.callThrough(); + + const obj = new Parse.Object('TestClass'); + await obj.save(); + expect(spy).toHaveBeenCalledTimes(0); + + const objError = new Parse.Object('TestClassError'); + await expectAsync(objError.save()).toBeRejected(); + // Not "beforeSave failed for TestClassError for user ..." + expect(spy).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/Controllers/LoggerController.js b/src/Controllers/LoggerController.js index 8466e5459a..6dac43518f 100644 --- a/src/Controllers/LoggerController.js +++ b/src/Controllers/LoggerController.js @@ -16,7 +16,7 @@ export const LogOrder = { ASCENDING: 'asc', }; -export const logLevels = ['error', 'warn', 'info', 'debug', 'verbose', 'silly']; +export const logLevels = ['error', 'warn', 'info', 'debug', 'verbose', 'silly', 'silent']; export class LoggerController extends AdaptableController { constructor(adapter, appId, options = { logLevel: 'info' }) { diff --git a/src/Routers/FunctionsRouter.js b/src/Routers/FunctionsRouter.js index bb4b959ebe..2e51cd167d 100644 --- a/src/Routers/FunctionsRouter.js +++ b/src/Routers/FunctionsRouter.js @@ -141,19 +141,21 @@ export class FunctionsRouter extends PromiseRouter { return new Promise(function (resolve, reject) { const userString = req.auth && req.auth.user ? req.auth.user.id : undefined; - const cleanInput = logger.truncateLogMessage(JSON.stringify(params)); const { success, error } = FunctionsRouter.createResponseObject( result => { try { - const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result)); - logger[req.config.logLevels.cloudFunctionSuccess]( - `Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Result: ${cleanResult}`, - { - functionName, - params, - user: userString, - } - ); + if (req.config.logLevels.cloudFunctionSuccess !== 'silent') { + const cleanInput = logger.truncateLogMessage(JSON.stringify(params)); + const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result)); + logger[req.config.logLevels.cloudFunctionSuccess]( + `Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Result: ${cleanResult}`, + { + functionName, + params, + user: userString, + } + ); + } resolve(result); } catch (e) { reject(e); @@ -161,16 +163,19 @@ export class FunctionsRouter extends PromiseRouter { }, error => { try { - logger[req.config.logLevels.cloudFunctionError]( - `Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` + - JSON.stringify(error), - { - functionName, - error, - params, - user: userString, - } - ); + if (req.config.logLevels.cloudFunctionError !== 'silent') { + const cleanInput = logger.truncateLogMessage(JSON.stringify(params)); + logger[req.config.logLevels.cloudFunctionError]( + `Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` + + JSON.stringify(error), + { + functionName, + error, + params, + user: userString, + } + ); + } reject(error); } catch (e) { reject(e); diff --git a/src/triggers.js b/src/triggers.js index 5c4755af54..e281bd87c6 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -376,6 +376,9 @@ function userIdForLog(auth) { } function logTriggerAfterHook(triggerType, className, input, auth, logLevel) { + if (logLevel === 'silent') { + return; + } const cleanInput = logger.truncateLogMessage(JSON.stringify(input)); logger[logLevel]( `${triggerType} triggered for ${className} for user ${userIdForLog( @@ -390,6 +393,9 @@ function logTriggerAfterHook(triggerType, className, input, auth, logLevel) { } function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth, logLevel) { + if (logLevel === 'silent') { + return; + } const cleanInput = logger.truncateLogMessage(JSON.stringify(input)); const cleanResult = logger.truncateLogMessage(JSON.stringify(result)); logger[logLevel]( @@ -405,6 +411,9 @@ function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth } function logTriggerErrorBeforeHook(triggerType, className, input, auth, error, logLevel) { + if (logLevel === 'silent') { + return; + } const cleanInput = logger.truncateLogMessage(JSON.stringify(input)); logger[logLevel]( `${triggerType} failed for ${className} for user ${userIdForLog( From f6a43f60fffc4e5676e6e851259b6afa182a2621 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Thu, 9 Nov 2023 20:33:08 -0600 Subject: [PATCH 2/3] improve test performance --- spec/CloudCodeLogger.spec.js | 8 +++++++- spec/helper.js | 24 ++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/spec/CloudCodeLogger.spec.js b/spec/CloudCodeLogger.spec.js index 4a22963bfd..abb11024eb 100644 --- a/spec/CloudCodeLogger.spec.js +++ b/spec/CloudCodeLogger.spec.js @@ -15,6 +15,13 @@ describe('Cloud Code Logger', () => { // useful to flip to false for fine tuning :). silent: true, logLevel: undefined, + logLevels: { + cloudFunctionError: 'error', + cloudFunctionSuccess: 'info', + triggerAfter: 'info', + triggerBeforeError: 'error', + triggerBeforeSuccess: 'info', + }, }) .then(() => { return Parse.User.signUp('tester', 'abc') @@ -337,7 +344,6 @@ describe('Cloud Code Logger', () => { it('should log cloud function execution using the silent log level', async () => { await reconfigureServer({ - silent: true, logLevels: { cloudFunctionSuccess: 'silent', cloudFunctionError: 'silent', diff --git a/spec/helper.js b/spec/helper.js index d393ef1d17..5fea77cbbf 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -131,6 +131,16 @@ const defaultConfiguration = { }, }; +if (silent) { + defaultConfiguration.logLevels = { + cloudFunctionSuccess: 'silent', + cloudFunctionError: 'silent', + triggerAfter: 'silent', + triggerBeforeError: 'silent', + triggerBeforeSuccess: 'silent', + }; +} + if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') { defaultConfiguration.cacheAdapter = new RedisCacheAdapter(); } @@ -251,8 +261,8 @@ afterEach(function (done) { }) .then(() => Parse.User.logOut()) .then( - () => { }, - () => { } + () => {}, + () => {} ) // swallow errors .then(() => { // Connection close events are not immediate on node 10+... wait a bit @@ -433,8 +443,8 @@ try { // Fetch test exclusion list testExclusionList = require('./testExclusionList.json'); console.log(`Using test exclusion list with ${testExclusionList.length} entries`); -} catch(error) { - if(error.code !== 'MODULE_NOT_FOUND') { +} catch (error) { + if (error.code !== 'MODULE_NOT_FOUND') { throw error; } } @@ -444,10 +454,8 @@ global.it_id = (id, func) => { if (testExclusionList.includes(id)) { return xit; } else { - if(func === undefined) - return it; - else - return func; + if (func === undefined) return it; + else return func; } }; From 46f900c43bf348aafe611a6175031fb4493d934f Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:06:25 +0100 Subject: [PATCH 3/3] refactor Signed-off-by: Manuel <5673677+mtrezza@users.noreply.github.com> --- spec/helper.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index 92878b21a2..04defa868d 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -455,8 +455,7 @@ global.it_id = (id, func) => { if (testExclusionList.includes(id)) { return xit; } else { - if (func === undefined) return it; - else return func; + return func || it; } };