feat: Add silent log level for Cloud Code (#8803)
This commit is contained in:
@@ -15,6 +15,13 @@ describe('Cloud Code Logger', () => {
|
|||||||
// useful to flip to false for fine tuning :).
|
// useful to flip to false for fine tuning :).
|
||||||
silent: true,
|
silent: true,
|
||||||
logLevel: undefined,
|
logLevel: undefined,
|
||||||
|
logLevels: {
|
||||||
|
cloudFunctionError: 'error',
|
||||||
|
cloudFunctionSuccess: 'info',
|
||||||
|
triggerAfter: 'info',
|
||||||
|
triggerBeforeError: 'error',
|
||||||
|
triggerBeforeSuccess: 'info',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return Parse.User.signUp('tester', 'abc')
|
return Parse.User.signUp('tester', 'abc')
|
||||||
@@ -334,4 +341,53 @@ describe('Cloud Code Logger', () => {
|
|||||||
expect(args[0]).toBe('Parse error: ');
|
expect(args[0]).toBe('Parse error: ');
|
||||||
expect(args[1].message).toBe('Object not found.');
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -132,6 +132,16 @@ const defaultConfiguration = {
|
|||||||
allowClientClassCreation: true,
|
allowClientClassCreation: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (silent) {
|
||||||
|
defaultConfiguration.logLevels = {
|
||||||
|
cloudFunctionSuccess: 'silent',
|
||||||
|
cloudFunctionError: 'silent',
|
||||||
|
triggerAfter: 'silent',
|
||||||
|
triggerBeforeError: 'silent',
|
||||||
|
triggerBeforeSuccess: 'silent',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
|
if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
|
||||||
defaultConfiguration.cacheAdapter = new RedisCacheAdapter();
|
defaultConfiguration.cacheAdapter = new RedisCacheAdapter();
|
||||||
}
|
}
|
||||||
@@ -434,8 +444,8 @@ try {
|
|||||||
// Fetch test exclusion list
|
// Fetch test exclusion list
|
||||||
testExclusionList = require('./testExclusionList.json');
|
testExclusionList = require('./testExclusionList.json');
|
||||||
console.log(`Using test exclusion list with ${testExclusionList.length} entries`);
|
console.log(`Using test exclusion list with ${testExclusionList.length} entries`);
|
||||||
} catch(error) {
|
} catch (error) {
|
||||||
if(error.code !== 'MODULE_NOT_FOUND') {
|
if (error.code !== 'MODULE_NOT_FOUND') {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,10 +455,7 @@ global.it_id = (id, func) => {
|
|||||||
if (testExclusionList.includes(id)) {
|
if (testExclusionList.includes(id)) {
|
||||||
return xit;
|
return xit;
|
||||||
} else {
|
} else {
|
||||||
if(func === undefined)
|
return func || it;
|
||||||
return it;
|
|
||||||
else
|
|
||||||
return func;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const LogOrder = {
|
|||||||
ASCENDING: 'asc',
|
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 {
|
export class LoggerController extends AdaptableController {
|
||||||
constructor(adapter, appId, options = { logLevel: 'info' }) {
|
constructor(adapter, appId, options = { logLevel: 'info' }) {
|
||||||
|
|||||||
@@ -141,19 +141,21 @@ export class FunctionsRouter extends PromiseRouter {
|
|||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
const userString = req.auth && req.auth.user ? req.auth.user.id : undefined;
|
const userString = req.auth && req.auth.user ? req.auth.user.id : undefined;
|
||||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
|
||||||
const { success, error } = FunctionsRouter.createResponseObject(
|
const { success, error } = FunctionsRouter.createResponseObject(
|
||||||
result => {
|
result => {
|
||||||
try {
|
try {
|
||||||
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
|
if (req.config.logLevels.cloudFunctionSuccess !== 'silent') {
|
||||||
logger[req.config.logLevels.cloudFunctionSuccess](
|
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
||||||
`Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Result: ${cleanResult}`,
|
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
|
||||||
{
|
logger[req.config.logLevels.cloudFunctionSuccess](
|
||||||
functionName,
|
`Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Result: ${cleanResult}`,
|
||||||
params,
|
{
|
||||||
user: userString,
|
functionName,
|
||||||
}
|
params,
|
||||||
);
|
user: userString,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
@@ -161,16 +163,19 @@ export class FunctionsRouter extends PromiseRouter {
|
|||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
try {
|
try {
|
||||||
logger[req.config.logLevels.cloudFunctionError](
|
if (req.config.logLevels.cloudFunctionError !== 'silent') {
|
||||||
`Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` +
|
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
||||||
JSON.stringify(error),
|
logger[req.config.logLevels.cloudFunctionError](
|
||||||
{
|
`Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` +
|
||||||
functionName,
|
JSON.stringify(error),
|
||||||
error,
|
{
|
||||||
params,
|
functionName,
|
||||||
user: userString,
|
error,
|
||||||
}
|
params,
|
||||||
);
|
user: userString,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
reject(error);
|
reject(error);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
|
|||||||
@@ -382,6 +382,9 @@ function userIdForLog(auth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logTriggerAfterHook(triggerType, className, input, auth, logLevel) {
|
function logTriggerAfterHook(triggerType, className, input, auth, logLevel) {
|
||||||
|
if (logLevel === 'silent') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(input));
|
const cleanInput = logger.truncateLogMessage(JSON.stringify(input));
|
||||||
logger[logLevel](
|
logger[logLevel](
|
||||||
`${triggerType} triggered for ${className} for user ${userIdForLog(
|
`${triggerType} triggered for ${className} for user ${userIdForLog(
|
||||||
@@ -396,6 +399,9 @@ function logTriggerAfterHook(triggerType, className, input, auth, logLevel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth, logLevel) {
|
function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth, logLevel) {
|
||||||
|
if (logLevel === 'silent') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(input));
|
const cleanInput = logger.truncateLogMessage(JSON.stringify(input));
|
||||||
const cleanResult = logger.truncateLogMessage(JSON.stringify(result));
|
const cleanResult = logger.truncateLogMessage(JSON.stringify(result));
|
||||||
logger[logLevel](
|
logger[logLevel](
|
||||||
@@ -411,6 +417,9 @@ function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logTriggerErrorBeforeHook(triggerType, className, input, auth, error, logLevel) {
|
function logTriggerErrorBeforeHook(triggerType, className, input, auth, error, logLevel) {
|
||||||
|
if (logLevel === 'silent') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(input));
|
const cleanInput = logger.truncateLogMessage(JSON.stringify(input));
|
||||||
logger[logLevel](
|
logger[logLevel](
|
||||||
`${triggerType} failed for ${className} for user ${userIdForLog(
|
`${triggerType} failed for ${className} for user ${userIdForLog(
|
||||||
|
|||||||
Reference in New Issue
Block a user