From 83874c8f570879a3e62b1b42abfafb0a1611d2d6 Mon Sep 17 00:00:00 2001 From: Arthur Cinader Date: Thu, 18 Aug 2016 18:41:04 -0700 Subject: [PATCH 1/3] Make parse-server cloud code logging much to parse.com legacy. (fixes #2501) 1. More closely mimic the wording. Include the user id. 2. Truncate input and result at 1k char. 3. Use more sensible metadata that would makes sense to index. The guideline I used was: if it makes sense to filter on, put it in metadata. If it makes sense to "free text" search on, then put it in the message. - file and console output, logging an object does not do what on might expect. For example, logging a function's "params": ``` expected: info: Ran cloud function aFunction for user qWHLVEsbEe with: Input: {"foo":"bar","bar":"baz"} Result: "it worked!" functionName=aFunction, params= { foo: "bar", "bar": baz }, user=qWHLVEsbEe what you actually get: info: Ran cloud function aFunction for user qWHLVEsbEe with: Input: {"foo":"bar","bar":"baz"} Result: "it worked!" functionName=aFunction, foo=bar, bar=baz, user=qWHLVEsbEe ``` - logging highly variable metadata is pretty useless for indexing when logs are sent to a logging repository like elastic search. In that use case, you want to index stuff you expect to filter on like user, hook type. - finally, putting the same input and result data in both the metadata and the message makes each message much larger with no additional value (that I know of anyway :). 4. Change some of the naming of functions in trigger.js to make future work easier. I was confused about why there were three logging functions in trigger and it took me awhile to get that before hooks and after hooks are logged differently. I just changed the names to make it obvious at first glance. 5. Add some try/catches to help any future futzers see syntax errors, etc instead of just hanging. Some log examples from unit test output: ``` info: Ran cloud function loggerTest for user YUD2os1i5B with: Input: {} Result: {} functionName=loggerTest, user=YUD2os1i5B info: beforeSave triggered for MyObject for user nssehQ3wtz: Input: {} Result: {} className=MyObject, triggerType=beforeSave, user=nssehQ3wtz info: afterSave triggered for MyObject for user XdznQgTD0p: Input: {"createdAt":"2016-08-19T01:11:31.249Z","updatedAt":"2016-08-19T01:11:31.249Z","objectId":"POoOOLL89U"} className=MyObject, triggerType=afterSave, user=XdznQgTD0p error: beforeSave failed for MyObject for user 7JHqCZgnhf: Input: {} Error: {"code":141,"message":"uh oh!"} className=MyObject, triggerType=beforeSave, code=141, message=uh oh!, user=7JHqCZgnhf info: Ran cloud function aFunction for user YR3nOoT3r9 with: Input: {"foo":"bar"} Result: "it worked!" functionName=aFunction, user=YR3nOoT3r9 error: Failed running cloud function aFunction for user Xm6NpOyuMC with: Input: {"foo":"bar"} Error: {"code":141,"message":"it failed!"} functionName=aFunction, code=141, message=it failed!, user=Xm6NpOyuMC info: Ran cloud function aFunction for user CK1lvkmaLg with: Input: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated) Result: {"longString":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus.\n\nSed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam... (truncated) functionName=aFunction, user=CK1lvkmaLg ``` --- spec/CloudCode.spec.js | 15 +++ spec/CloudCodeLogger.spec.js | 169 +++++++++++++++++++++++++--- spec/support/lorem.txt | 5 + src/Controllers/LoggerController.js | 15 ++- src/Routers/FunctionsRouter.js | 41 ++++--- src/triggers.js | 51 +++++---- 6 files changed, 245 insertions(+), 51 deletions(-) create mode 100644 spec/support/lorem.txt diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index cd28659f73..87fe6d696d 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -59,6 +59,21 @@ describe('Cloud Code', () => { }) }); + it('returns an error', (done) => { + Parse.Cloud.define('cloudCodeWithError', (req, res) => { + foo.bar(); + res.success('I better throw an error.'); + }); + + Parse.Cloud.run('cloudCodeWithError') + .then( + a => done.fail('should not succeed'), + e => { + expect(e).toEqual(new Parse.Error(1, undefined)); + done(); + }); + }); + it('beforeSave rejection with custom error code', function(done) { Parse.Cloud.beforeSave('BeforeSaveFailWithErrorCode', function (req, res) { res.error(999, 'Nope'); diff --git a/spec/CloudCodeLogger.spec.js b/spec/CloudCodeLogger.spec.js index ac1b15aaed..2ce197dba5 100644 --- a/spec/CloudCodeLogger.spec.js +++ b/spec/CloudCodeLogger.spec.js @@ -2,27 +2,47 @@ var LoggerController = require('../src/Controllers/LoggerController').LoggerController; var WinstonLoggerAdapter = require('../src/Adapters/Logger/WinstonLoggerAdapter').WinstonLoggerAdapter; +const fs = require('fs'); +const loremFile = __dirname + '/support/lorem.txt'; + describe("Cloud Code Logger", () => { - it("should expose log to functions", (done) => { + let user; + + beforeEach(done => { + Parse.User.enableUnsafeCurrentUser(); + return reconfigureServer({ + // useful to flip to false for fine tuning :). + silent: true, + }).then(() => { + return Parse.User.signUp('tester', 'abc') + .then(loggedInUser => user = loggedInUser) + .then(() => Parse.User.logIn(user.get('username'), 'abc')) + .then(() => done()) + }); + }); + + // Note that helpers takes care of logout. + // see helpers.js:afterEach + + it("should expose log to functions", done => { var logController = new LoggerController(new WinstonLoggerAdapter()); Parse.Cloud.define("loggerTest", (req, res) => { - req.log.info('logTest', 'info log', {info: 'some log' }); - req.log.error('logTest','error log', {error: 'there was an error'}); + req.log.info('logTest', 'info log', { info: 'some log' }); + req.log.error('logTest', 'error log', { error: 'there was an error' }); res.success({}); }); Parse.Cloud.run('loggerTest').then(() => { - return logController.getLogs({from: Date.now() - 500, size: 1000}); + return logController.getLogs({ from: Date.now() - 500, size: 1000 }); }).then((res) => { expect(res.length).not.toBe(0); - let lastLogs = res.slice(0, 3); + let lastLogs = res.slice(0, 3); let cloudFunctionMessage = lastLogs[0]; let errorMessage = lastLogs[1]; let infoMessage = lastLogs[2]; expect(cloudFunctionMessage.level).toBe('info'); - expect(cloudFunctionMessage.params).toEqual({}); - expect(cloudFunctionMessage.message).toEqual('Ran cloud function loggerTest with:\nInput: {}\nResult: {}'); + expect(cloudFunctionMessage.message).toMatch(/Ran cloud function loggerTest for user [^ ]* with:\n Input: {}\n Result: {}/); expect(cloudFunctionMessage.functionName).toEqual('loggerTest'); expect(errorMessage.level).toBe('error'); expect(errorMessage.error).toBe('there was an error'); @@ -38,23 +58,24 @@ describe("Cloud Code Logger", () => { var logController = new LoggerController(new WinstonLoggerAdapter()); Parse.Cloud.beforeSave("MyObject", (req, res) => { - req.log.info('beforeSave MyObject', 'info log', {info: 'some log' }); - req.log.error('beforeSave MyObject','error log', {error: 'there was an error'}); + req.log.info('beforeSave MyObject', 'info log', { info: 'some log' }); + req.log.error('beforeSave MyObject', 'error log', { error: 'there was an error' }); res.success({}); }); let obj = new Parse.Object('MyObject'); obj.save().then(() => { - return logController.getLogs({from: Date.now() - 500, size: 1000}) + return logController.getLogs({ from: Date.now() - 500, size: 1000 }) }).then((res) => { expect(res.length).not.toBe(0); - let lastLogs = res.slice(0, 3); + let lastLogs = res.slice(0, 3); let cloudTriggerMessage = lastLogs[0]; let errorMessage = lastLogs[1]; let infoMessage = lastLogs[2]; expect(cloudTriggerMessage.level).toBe('info'); - expect(cloudTriggerMessage.input).toEqual({}); - expect(cloudTriggerMessage.message).toEqual('beforeSave triggered for MyObject\nInput: {}\nResult: {}'); + expect(cloudTriggerMessage.triggerType).toEqual('beforeSave'); + expect(cloudTriggerMessage.message).toMatch(/beforeSave triggered for MyObject for user [^ ]*\n Input: {}\n Result: {}/); + expect(cloudTriggerMessage.user).toBe(user.id); expect(errorMessage.level).toBe('error'); expect(errorMessage.error).toBe('there was an error'); expect(errorMessage.message).toBe('beforeSave MyObject error log'); @@ -64,4 +85,126 @@ describe("Cloud Code Logger", () => { done(); }); }); + + it('should truncate really long lines when asked to', () => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + const longString = fs.readFileSync(loremFile, 'utf8'); + const truncatedString = logController.truncateLogMessage(longString); + expect(truncatedString.length).toBe(1015); // truncate length + the string '... (truncated)' + }); + + it('should truncate input and result of long lines', done => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + const longString = fs.readFileSync(loremFile, 'utf8'); + Parse.Cloud.define('aFunction', (req, res) => { + res.success(req.params); + }); + + Parse.Cloud.run('aFunction', { longString }) + .then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 })) + .then(logs => { + const log = logs[0]; + expect(log.level).toEqual('info'); + expect(log.message).toMatch( + /Ran cloud function aFunction for user [^ ]* with:\n Input: {.*?\(truncated\)$/m); + done(); + }) + .then(null, e => done.fail(e)); + }); + + it('should log an afterSave', done => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + Parse.Cloud.afterSave("MyObject", (req) => { }); + new Parse.Object('MyObject') + .save() + .then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 })) + .then((logs) => { + const log = logs[0]; + expect(log.triggerType).toEqual('afterSave'); + done(); + }) + // catch errors - not that the error is actually useful :( + .then(null, e => done.fail(e)); + }); + + it('should log a denied beforeSave', done => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + Parse.Cloud.beforeSave("MyObject", (req, res) => { + res.error('uh oh!'); + }); + + new Parse.Object('MyObject') + .save() + .then( + () => done.fail('this is not supposed to succeed'), + e => logController.getLogs({ from: Date.now() - 500, size: 1000 }) + ) + .then(logs => { + const log = logs[1]; // 0 is the 'uh oh!' from rejection... + expect(log.level).toEqual('error'); + expect(log.error).toEqual({ code: 141, message: 'uh oh!' }); + done() + }); + }); + + it('should log cloud function success', done => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + + Parse.Cloud.define('aFunction', (req, res) => { + res.success('it worked!'); + }); + + Parse.Cloud.run('aFunction', { foo: 'bar' }) + .then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 })) + .then(logs => { + const log = logs[0]; + expect(log.level).toEqual('info'); + expect(log.message).toMatch( + /Ran cloud function aFunction for user [^ ]* with:\n Input: {"foo":"bar"}\n Result: "it worked!/); + done(); + }); + }); + + it('should log cloud function failure', done => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + + Parse.Cloud.define('aFunction', (req, res) => { + res.error('it failed!'); + }); + + Parse.Cloud.run('aFunction', { foo: 'bar' }) + .then(null, () => logController.getLogs({ from: Date.now() - 500, size: 1000 })) + .then(logs => { + const log = logs[1]; + expect(log.level).toEqual('error'); + expect(log.message).toMatch( + /Failed running cloud function aFunction for user [^ ]* with:\n Input: {"foo":"bar"}\n Error: {"code":141,"message":"it failed!"}/); + done(); + }); + }); + + xit('should log a changed beforeSave indicating a change', done => { + const logController = new LoggerController(new WinstonLoggerAdapter()); + + Parse.Cloud.beforeSave("MyObject", (req, res) => { + const myObj = req.object; + myObj.set('aChange', true); + res.success(myObj); + }); + + new Parse.Object('MyObject') + .save() + .then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 })) + .then(logs => { + // expect the log to indicate that it has changed + /* + Here's what it looks like on parse.com... + + Input: {"original":{"clientVersion":"1","createdAt":"2016-06-02T05:29:08.694Z","image":{"__type":"File","name":"tfss-xxxxxxxx.png","url":"http://files.parsetfss.com/xxxxxxxx.png"},"lastScanDate":{"__type":"Date","iso":"2016-06-02T05:28:58.135Z"},"localIdentifier":"XXXXX","objectId":"OFHMX7ZUcI","status":... (truncated) + Result: Update changed to {"object":{"__type":"Pointer","className":"Emoticode","objectId":"ksrq7z3Ehc"},"imageThumb":{"__type":"File","name":"tfss-xxxxxxx.png","url":"http://files.parsetfss.com/xxxxx.png"},"status":"success"} + */ + done(); + }) + .then(null, e => done.fail(JSON.stringify(e))); + }).pend('needs more work.....'); }); diff --git a/spec/support/lorem.txt b/spec/support/lorem.txt new file mode 100644 index 0000000000..2e7cd518cc --- /dev/null +++ b/spec/support/lorem.txt @@ -0,0 +1,5 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lobortis semper diam, ac euismod diam pharetra sed. Etiam eget efficitur neque. Proin nec diam mi. Sed ut purus dolor. Nulla nulla nibh, ornare vitae ornare et, scelerisque rutrum eros. Mauris venenatis tincidunt turpis a mollis. Donec gravida eget enim in luctus. + +Sed porttitor commodo orci, ut pretium eros convallis eget. Curabitur pretium velit in odio dictum luctus. Vivamus ac tristique arcu, a semper tellus. Morbi euismod purus dapibus vestibulum sagittis. Nunc dapibus vehicula leo at scelerisque. Donec porta mauris quis nulla imperdiet consectetur. Curabitur sagittis eleifend arcu eget elementum. Aenean interdum tincidunt ornare. Pellentesque sit amet interdum tortor. Pellentesque blandit nisl eget euismod consequat. Etiam feugiat felis sit amet porta pulvinar. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Nulla faucibus sem ipsum, at rhoncus diam pulvinar at. Vivamus consectetur, diam at aliquet vestibulum, sem purus elementum nulla, eget tincidunt nullam. diff --git a/src/Controllers/LoggerController.js b/src/Controllers/LoggerController.js index 5b1946e9e6..512c0c8a8e 100644 --- a/src/Controllers/LoggerController.js +++ b/src/Controllers/LoggerController.js @@ -4,6 +4,8 @@ import AdaptableController from './AdaptableController'; import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter'; const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000; +const logStringTruncateLength = 1000; +const truncationMarker = '... (truncated)'; export const LogLevel = { INFO: 'info', @@ -16,7 +18,7 @@ export const LogOrder = { } export class LoggerController extends AdaptableController { - + log(level, args) { args = [].concat(level, [...args]); this.adapter.log.apply(this.adapter, args); @@ -25,7 +27,7 @@ export class LoggerController extends AdaptableController { info() { return this.log('info', arguments); } - + error() { return this.log('error', arguments); } @@ -59,6 +61,15 @@ export class LoggerController extends AdaptableController { return null; } + truncateLogMessage(string) { + if (string && string.length > logStringTruncateLength) { + const truncated = string.substring(0, logStringTruncateLength) + truncationMarker; + return truncated; + } + + return string; + } + static parseOptions(options = {}) { let from = LoggerController.validDateTime(options.from) || new Date(Date.now() - 7 * MILLISECONDS_IN_A_DAY); diff --git a/src/Routers/FunctionsRouter.js b/src/Routers/FunctionsRouter.js index c61c59fb7f..afcb322262 100644 --- a/src/Routers/FunctionsRouter.js +++ b/src/Routers/FunctionsRouter.js @@ -78,20 +78,33 @@ export class FunctionsRouter extends PromiseRouter { } return new Promise(function (resolve, reject) { - var response = FunctionsRouter.createResponseObject((result) => { - logger.info(`Ran cloud function ${req.params.functionName} with:\nInput: ${JSON.stringify(params)}\nResult: ${JSON.stringify(result.response.result)}`, { - functionName: req.params.functionName, - params, - result: result.response.result - }); - resolve(result); - }, (error) => { - logger.error(`Failed running cloud function ${req.params.functionName} with:\nInput: ${JSON.stringify(params)}\Error: ${JSON.stringify(error)}`, { - functionName: req.params.functionName, - params, - error - }); - reject(error); + const userString = (req.auth && req.auth.user) ? req.auth.user.id : undefined; + const cleanInput = logger.truncateLogMessage(JSON.stringify(params)); + var response = FunctionsRouter.createResponseObject((result) => { + try { + const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result)); + logger.info(`Ran cloud function ${req.params.functionName} for user ${userString} ` + + `with:\n Input: ${cleanInput }\n Result: ${cleanResult }`, { + functionName: req.params.functionName, + user: userString, + }); + resolve(result); + } catch (e) { + reject(e); + } + }, (error) => { + try { + logger.error(`Failed running cloud function ${req.params.functionName} for ` + + `user ${userString} with:\n Input: ${cleanInput}\n Error: ` + + JSON.stringify(error), { + functionName: req.params.functionName, + error, + user: userString + }); + reject(error); + } catch (e) { + reject(e); + } }); // Force the keys before the function calls. Parse.applicationId = req.config.applicationId; diff --git a/src/triggers.js b/src/triggers.js index e167e4c7a6..baab4c5dd1 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -153,32 +153,36 @@ export function getResponseObject(request, resolve, reject) { } }; -function logTrigger(triggerType, className, input) { - if (triggerType.indexOf('after') != 0) { - return; - } - logger.info(`${triggerType} triggered for ${className}\nInput: ${JSON.stringify(input)}`, { +function userIdForLog(auth) { + return (auth && auth.user) ? auth.user.id : undefined; +} + +function logTriggerAfterHook(triggerType, className, input, auth) { + const cleanInput = logger.truncateLogMessage(JSON.stringify(input)); + logger.info(`${triggerType} triggered for ${className} for user ${userIdForLog(auth)}:\n Input: ${cleanInput}`, { className, triggerType, - input + user: userIdForLog(auth) }); } -function logTriggerSuccess(triggerType, className, input, result) { - logger.info(`${triggerType} triggered for ${className}\nInput: ${JSON.stringify(input)}\nResult: ${JSON.stringify(result)}`, { +function logTriggerSuccessBeforeHook(triggerType, className, input, result, auth) { + const cleanInput = logger.truncateLogMessage(JSON.stringify(input)); + const cleanResult = logger.truncateLogMessage(JSON.stringify(result)); + logger.info(`${triggerType} triggered for ${className} for user ${userIdForLog(auth)}:\n Input: ${cleanInput}\n Result: ${cleanResult}`, { className, triggerType, - input, - result + user: userIdForLog(auth) }); } -function logTriggerError(triggerType, className, input, error) { - logger.error(`${triggerType} failed for ${className}\nInput: ${JSON.stringify(input)}\Error: ${JSON.stringify(error)}`, { +function logTriggerErrorBeforeHook(triggerType, className, input, auth, error) { + const cleanInput = logger.truncateLogMessage(JSON.stringify(input)); + logger.error(`${triggerType} failed for ${className} for user ${userIdForLog(auth)}:\n Input: ${cleanInput}\n Error: ${JSON.stringify(error)}`, { className, triggerType, - input, - error + error, + user: userIdForLog(auth) }); } @@ -187,7 +191,7 @@ function logTriggerError(triggerType, className, input, error) { // Will resolve successfully if no trigger is configured // Resolves to an object, empty or containing an object key. A beforeSave // trigger will set the object key to the rest format object to save. -// originalParseObject is optional, we only need that for befote/afterSave functions +// originalParseObject is optional, we only need that for before/afterSave functions export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObject, config) { if (!parseObject) { return Promise.resolve({}); @@ -197,25 +201,28 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj if (!trigger) return resolve(); var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config); var response = getResponseObject(request, (object) => { - logTriggerSuccess(triggerType, parseObject.className, parseObject.toJSON(), object); + logTriggerSuccessBeforeHook( + triggerType, parseObject.className, parseObject.toJSON(), object, auth); resolve(object); }, (error) => { - logTriggerError(triggerType, parseObject.className, parseObject.toJSON(), error); + logTriggerErrorBeforeHook( + triggerType, parseObject.className, parseObject.toJSON(), auth, error); reject(error); }); // Force the current Parse app before the trigger Parse.applicationId = config.applicationId; Parse.javascriptKey = config.javascriptKey || ''; Parse.masterKey = config.masterKey; - // For the afterSuccess / afterDelete - logTrigger(triggerType, parseObject.className, parseObject.toJSON()); - //AfterSave and afterDelete triggers can return a promise, which if they do, needs to be resolved before this promise is resolved, - //so trigger execution is synced with RestWrite.execute() call. - //If triggers do not return a promise, they can run async code parallel to the RestWrite.execute() call. + // AfterSave and afterDelete triggers can return a promise, which if they + // do, needs to be resolved before this promise is resolved, + // so trigger execution is synced with RestWrite.execute() call. + // If triggers do not return a promise, they can run async code parallel + // to the RestWrite.execute() call. var triggerPromise = trigger(request, response); if(triggerType === Types.afterSave || triggerType === Types.afterDelete) { + logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth); if(triggerPromise && typeof triggerPromise.then === "function") { return triggerPromise.then(resolve, resolve); } From 008dd56d762fb56eaf169bb1aa28e5d47409bf56 Mon Sep 17 00:00:00 2001 From: Arthur Cinader Date: Fri, 19 Aug 2016 08:24:16 -0700 Subject: [PATCH 2/3] Implement PR comments: - add back params to metadata and add back to the test - use screaming snake case for conts --- spec/CloudCodeLogger.spec.js | 1 + src/Controllers/LoggerController.js | 6 +++--- src/Routers/FunctionsRouter.js | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/CloudCodeLogger.spec.js b/spec/CloudCodeLogger.spec.js index 2ce197dba5..a10b894b41 100644 --- a/spec/CloudCodeLogger.spec.js +++ b/spec/CloudCodeLogger.spec.js @@ -42,6 +42,7 @@ describe("Cloud Code Logger", () => { let errorMessage = lastLogs[1]; let infoMessage = lastLogs[2]; expect(cloudFunctionMessage.level).toBe('info'); + expect(cloudFunctionMessage.params).toEqual({}); expect(cloudFunctionMessage.message).toMatch(/Ran cloud function loggerTest for user [^ ]* with:\n Input: {}\n Result: {}/); expect(cloudFunctionMessage.functionName).toEqual('loggerTest'); expect(errorMessage.level).toBe('error'); diff --git a/src/Controllers/LoggerController.js b/src/Controllers/LoggerController.js index 512c0c8a8e..9a47ff8b2e 100644 --- a/src/Controllers/LoggerController.js +++ b/src/Controllers/LoggerController.js @@ -4,7 +4,7 @@ import AdaptableController from './AdaptableController'; import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter'; const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000; -const logStringTruncateLength = 1000; +const LOG_STRING_TRUCATE_LENGTH = 1000; const truncationMarker = '... (truncated)'; export const LogLevel = { @@ -62,8 +62,8 @@ export class LoggerController extends AdaptableController { } truncateLogMessage(string) { - if (string && string.length > logStringTruncateLength) { - const truncated = string.substring(0, logStringTruncateLength) + truncationMarker; + if (string && string.length > LOG_STRING_TRUCATE_LENGTH) { + const truncated = string.substring(0, LOG_STRING_TRUCATE_LENGTH) + truncationMarker; return truncated; } diff --git a/src/Routers/FunctionsRouter.js b/src/Routers/FunctionsRouter.js index afcb322262..6591f31a5f 100644 --- a/src/Routers/FunctionsRouter.js +++ b/src/Routers/FunctionsRouter.js @@ -86,6 +86,7 @@ export class FunctionsRouter extends PromiseRouter { logger.info(`Ran cloud function ${req.params.functionName} for user ${userString} ` + `with:\n Input: ${cleanInput }\n Result: ${cleanResult }`, { functionName: req.params.functionName, + params, user: userString, }); resolve(result); @@ -99,6 +100,7 @@ export class FunctionsRouter extends PromiseRouter { + JSON.stringify(error), { functionName: req.params.functionName, error, + params, user: userString }); reject(error); From 2e6f00b47ee9a07387d02b58bdbdf5ce63dcd4d1 Mon Sep 17 00:00:00 2001 From: Arthur Cinader Date: Fri, 19 Aug 2016 09:05:02 -0700 Subject: [PATCH 3/3] fix typo --- src/Controllers/LoggerController.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Controllers/LoggerController.js b/src/Controllers/LoggerController.js index 9a47ff8b2e..59a6ab943a 100644 --- a/src/Controllers/LoggerController.js +++ b/src/Controllers/LoggerController.js @@ -4,7 +4,7 @@ import AdaptableController from './AdaptableController'; import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter'; const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000; -const LOG_STRING_TRUCATE_LENGTH = 1000; +const LOG_STRING_TRUNCATE_LENGTH = 1000; const truncationMarker = '... (truncated)'; export const LogLevel = { @@ -62,8 +62,8 @@ export class LoggerController extends AdaptableController { } truncateLogMessage(string) { - if (string && string.length > LOG_STRING_TRUCATE_LENGTH) { - const truncated = string.substring(0, LOG_STRING_TRUCATE_LENGTH) + truncationMarker; + if (string && string.length > LOG_STRING_TRUNCATE_LENGTH) { + const truncated = string.substring(0, LOG_STRING_TRUNCATE_LENGTH) + truncationMarker; return truncated; }