diff --git a/spec/CloudCodeLogger.spec.js b/spec/CloudCodeLogger.spec.js index 54c03a534b..145a6155b9 100644 --- a/spec/CloudCodeLogger.spec.js +++ b/spec/CloudCodeLogger.spec.js @@ -16,9 +16,14 @@ describe("Cloud Code Logger", () => { return logController.getLogs({from: Date.now() - 500, size: 1000}); }).then((res) => { expect(res.length).not.toBe(0); - let lastLogs = res.slice(0, 2); - let errorMessage = lastLogs[0]; - let infoMessage = lastLogs[1]; + 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.functionName).toEqual('loggerTest'); expect(errorMessage.level).toBe('error'); expect(errorMessage.error).toBe('there was an error'); expect(errorMessage.message).toBe('logTest error log'); @@ -43,9 +48,13 @@ describe("Cloud Code Logger", () => { return logController.getLogs({from: Date.now() - 500, size: 1000}) }).then((res) => { expect(res.length).not.toBe(0); - let lastLogs = res.slice(0, 2); - let errorMessage = lastLogs[0]; - let infoMessage = lastLogs[1]; + 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(errorMessage.level).toBe('error'); expect(errorMessage.error).toBe('there was an error'); expect(errorMessage.message).toBe('beforeSave MyObject error log'); diff --git a/src/Routers/FunctionsRouter.js b/src/Routers/FunctionsRouter.js index 604a4a75ef..41df21e954 100644 --- a/src/Routers/FunctionsRouter.js +++ b/src/Routers/FunctionsRouter.js @@ -6,6 +6,7 @@ var express = require('express'), import PromiseRouter from '../PromiseRouter'; import _ from 'lodash'; +import { logger } from '../logger'; function parseObject(obj) { if (Array.isArray(obj)) { @@ -76,7 +77,21 @@ export class FunctionsRouter extends PromiseRouter { } return new Promise(function (resolve, reject) { - var response = FunctionsRouter.createResponseObject(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.resut + }); + 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); + }); // Force the keys before the function calls. Parse.applicationId = req.config.applicationId; Parse.javascriptKey = req.config.javascriptKey; diff --git a/src/rest.js b/src/rest.js index 83cacd380e..91cf9ae3a3 100644 --- a/src/rest.js +++ b/src/rest.js @@ -94,7 +94,7 @@ function del(config, auth, className, objectId, clientSDK) { // Returns a promise for a {response, status, location} object. function create(config, auth, className, restObject, clientSDK) { enforceRoleSecurity('create', className, auth); - var write = new RestWrite(config, auth, className, null, restObject, clientSDK); + var write = new RestWrite(config, auth, className, null, restObject, null, clientSDK); return write.execute(); } diff --git a/src/triggers.js b/src/triggers.js index 8b393605b1..ea1853f99e 100644 --- a/src/triggers.js +++ b/src/triggers.js @@ -1,6 +1,7 @@ // triggers.js import Parse from 'parse/node'; import AppCache from './cache'; +import { logger } from './logger'; export const Types = { beforeSave: 'beforeSave', @@ -152,6 +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)}`, { + className, + triggerType, + input + }); +} + +function logTriggerSuccess(triggerType, className, input, result) { + logger.info(`${triggerType} triggered for ${className}\nInput: ${JSON.stringify(input)}\nResult: ${JSON.stringify(result)}`, { + className, + triggerType, + input, + result + }); +} + +function logTriggerError(triggerType, className, input, error) { + logger.error(`${triggerType} failed for ${className}\nInput: ${JSON.stringify(input)}\Error: ${JSON.stringify(error)}`, { + className, + triggerType, + input, + error + }); +} + + // To be used as part of the promise chain when saving/deleting an object // Will resolve successfully if no trigger is configured // Resolves to an object, empty or containing an object key. A beforeSave @@ -165,11 +196,19 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj var trigger = getTrigger(parseObject.className, triggerType, config.applicationId); if (!trigger) return resolve(); var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config); - var response = getResponseObject(request, resolve, reject); + var response = getResponseObject(request, (object) => { + logTriggerSuccess(triggerType, parseObject.className, parseObject.toJSON(), object); + resolve(object); + }, (error) => { + logTriggerError(triggerType, parseObject.className, parseObject.toJSON(), 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()); trigger(request, response); }); };