Skip to content

Commit

Permalink
feat: Add silent log level for Cloud Code (#8803)
Browse files Browse the repository at this point in the history
  • Loading branch information
dplewis committed Mar 21, 2024
1 parent 7d84b24 commit 5f81efb
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 27 deletions.
56 changes: 56 additions & 0 deletions spec/CloudCodeLogger.spec.js
Expand Up @@ -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')
Expand Down Expand Up @@ -334,4 +341,53 @@ 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({
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);
});
});
19 changes: 13 additions & 6 deletions spec/helper.js
Expand Up @@ -132,6 +132,16 @@ const defaultConfiguration = {
allowClientClassCreation: true,
};

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();
}
Expand Down Expand Up @@ -434,8 +444,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;
}
}
Expand All @@ -445,10 +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;
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/LoggerController.js
Expand Up @@ -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' }) {
Expand Down
45 changes: 25 additions & 20 deletions src/Routers/FunctionsRouter.js
Expand Up @@ -141,36 +141,41 @@ 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);
}
},
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);
Expand Down
9 changes: 9 additions & 0 deletions src/triggers.js
Expand Up @@ -382,6 +382,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(
Expand All @@ -396,6 +399,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](
Expand All @@ -411,6 +417,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(
Expand Down

0 comments on commit 5f81efb

Please sign in to comment.