Exposes the loggerAdapter as log to Cloud Functions and Triggers (#1565)
This allows access to logging inside cloud code and triggers via
request.log.info
request.log.error
This commit is contained in:
committed by
Florent Vilmart
parent
2d94a885d2
commit
6e9529f81c
61
spec/CloudCodeLogger.spec.js
Normal file
61
spec/CloudCodeLogger.spec.js
Normal file
@@ -0,0 +1,61 @@
|
||||
'use strict';
|
||||
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
||||
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
||||
|
||||
describe("Cloud Code Logger", () => {
|
||||
|
||||
it("should expose log to functions", (done) => {
|
||||
var logController = new LoggerController(new FileLoggerAdapter());
|
||||
|
||||
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'});
|
||||
res.success({});
|
||||
});
|
||||
|
||||
Parse.Cloud.run('loggerTest').then(() => {
|
||||
Parse.Cloud._removeHook('Functions', 'logTest');
|
||||
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];
|
||||
expect(errorMessage.level).toBe('error');
|
||||
expect(errorMessage.error).toBe('there was an error');
|
||||
expect(errorMessage.message).toBe('logTest error log');
|
||||
expect(infoMessage.level).toBe('info');
|
||||
expect(infoMessage.info).toBe('some log');
|
||||
expect(infoMessage.message).toBe('logTest info log');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should expose log to trigger", (done) => {
|
||||
var logController = new LoggerController(new FileLoggerAdapter());
|
||||
|
||||
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'});
|
||||
res.success({});
|
||||
});
|
||||
|
||||
let obj = new Parse.Object('MyObject');
|
||||
obj.save().then(() => {
|
||||
Parse.Cloud._removeHook('Triggers', 'beforeSave', 'MyObject');
|
||||
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];
|
||||
expect(errorMessage.level).toBe('error');
|
||||
expect(errorMessage.error).toBe('there was an error');
|
||||
expect(errorMessage.message).toBe('beforeSave MyObject error log');
|
||||
expect(infoMessage.level).toBe('info');
|
||||
expect(infoMessage.info).toBe('some log');
|
||||
expect(infoMessage.message).toBe('beforeSave MyObject info log');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,8 @@ describe('info logs', () => {
|
||||
var fileLoggerAdapter = new FileLoggerAdapter();
|
||||
fileLoggerAdapter.info('testing info logs', () => {
|
||||
fileLoggerAdapter.query({
|
||||
size: 1,
|
||||
from: new Date(Date.now() - 500),
|
||||
size: 100,
|
||||
level: 'info'
|
||||
}, (results) => {
|
||||
if(results.length == 0) {
|
||||
@@ -28,7 +29,8 @@ describe('error logs', () => {
|
||||
var fileLoggerAdapter = new FileLoggerAdapter();
|
||||
fileLoggerAdapter.error('testing error logs', () => {
|
||||
fileLoggerAdapter.query({
|
||||
size: 1,
|
||||
from: new Date(Date.now() - 500),
|
||||
size: 100,
|
||||
level: 'error'
|
||||
}, (results) => {
|
||||
if(results.length == 0) {
|
||||
|
||||
@@ -162,7 +162,7 @@ RestWrite.prototype.runBeforeTrigger = function() {
|
||||
updatedObject.set(this.sanitizedData());
|
||||
|
||||
return Promise.resolve().then(() => {
|
||||
return triggers.maybeRunTrigger(triggers.Types.beforeSave, this.auth, updatedObject, originalObject, this.config.applicationId);
|
||||
return triggers.maybeRunTrigger(triggers.Types.beforeSave, this.auth, updatedObject, originalObject, this.config);
|
||||
}).then((response) => {
|
||||
if (response && response.object) {
|
||||
this.data = response.object;
|
||||
@@ -824,7 +824,7 @@ RestWrite.prototype.runAfterTrigger = function() {
|
||||
this.config.liveQueryController.onAfterSave(updatedObject.className, updatedObject, originalObject);
|
||||
|
||||
// Run afterSave trigger
|
||||
triggers.maybeRunTrigger(triggers.Types.afterSave, this.auth, updatedObject, originalObject, this.config.applicationId);
|
||||
triggers.maybeRunTrigger(triggers.Types.afterSave, this.auth, updatedObject, originalObject, this.config);
|
||||
};
|
||||
|
||||
// A helper to figure out what location this operation happens at.
|
||||
|
||||
@@ -7,11 +7,11 @@ var express = require('express'),
|
||||
import PromiseRouter from '../PromiseRouter';
|
||||
|
||||
export class FunctionsRouter extends PromiseRouter {
|
||||
|
||||
|
||||
mountRoutes() {
|
||||
this.route('POST', '/functions/:functionName', FunctionsRouter.handleCloudFunction);
|
||||
}
|
||||
|
||||
|
||||
static createResponseObject(resolve, reject) {
|
||||
return {
|
||||
success: function(result) {
|
||||
@@ -26,19 +26,19 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static handleCloudFunction(req) {
|
||||
var applicationId = req.config.applicationId;
|
||||
var theFunction = triggers.getFunction(req.params.functionName, applicationId);
|
||||
var theValidator = triggers.getValidator(req.params.functionName, applicationId);
|
||||
if (theFunction) {
|
||||
|
||||
const params = Object.assign({}, req.body, req.query);
|
||||
var request = {
|
||||
params: params,
|
||||
master: req.auth && req.auth.isMaster,
|
||||
user: req.auth && req.auth.user,
|
||||
installationId: req.info.installationId
|
||||
installationId: req.info.installationId,
|
||||
log: req.config.loggerController && req.config.loggerController.adapter
|
||||
};
|
||||
|
||||
if (theValidator && typeof theValidator === "function") {
|
||||
|
||||
@@ -52,7 +52,7 @@ function del(config, auth, className, objectId) {
|
||||
inflatedObject = Parse.Object.fromJSON(response.results[0]);
|
||||
// Notify LiveQuery server if possible
|
||||
config.liveQueryController.onAfterDelete(inflatedObject.className, inflatedObject);
|
||||
return triggers.maybeRunTrigger(triggers.Types.beforeDelete, auth, inflatedObject, null, config.applicationId);
|
||||
return triggers.maybeRunTrigger(triggers.Types.beforeDelete, auth, inflatedObject, null, config);
|
||||
}
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
||||
'Object not found for delete.');
|
||||
@@ -79,7 +79,7 @@ function del(config, auth, className, objectId) {
|
||||
objectId: objectId
|
||||
}, options);
|
||||
}).then(() => {
|
||||
triggers.maybeRunTrigger(triggers.Types.afterDelete, auth, inflatedObject, null, config.applicationId);
|
||||
triggers.maybeRunTrigger(triggers.Types.afterDelete, auth, inflatedObject, null, config);
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const baseStore = function() {
|
||||
base[key] = {};
|
||||
return base;
|
||||
}, {});
|
||||
|
||||
|
||||
return Object.freeze({
|
||||
Functions,
|
||||
Validators,
|
||||
@@ -63,7 +63,7 @@ export function getTrigger(className, triggerType, applicationId) {
|
||||
throw "Missing ApplicationID";
|
||||
}
|
||||
var manager = _triggerStore[applicationId]
|
||||
if (manager
|
||||
if (manager
|
||||
&& manager.Triggers
|
||||
&& manager.Triggers[triggerType]
|
||||
&& manager.Triggers[triggerType][className]) {
|
||||
@@ -92,15 +92,18 @@ export function getValidator(functionName, applicationId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getRequestObject(triggerType, auth, parseObject, originalParseObject) {
|
||||
export function getRequestObject(triggerType, auth, parseObject, originalParseObject, config) {
|
||||
var request = {
|
||||
triggerName: triggerType,
|
||||
object: parseObject,
|
||||
master: false
|
||||
master: false,
|
||||
log: config.loggerController && config.loggerController.adapter
|
||||
};
|
||||
|
||||
if (originalParseObject) {
|
||||
request.original = originalParseObject;
|
||||
}
|
||||
|
||||
if (!auth) {
|
||||
return request;
|
||||
}
|
||||
@@ -145,19 +148,19 @@ export function getResponseObject(request, resolve, reject) {
|
||||
// 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
|
||||
export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObject, applicationId) {
|
||||
export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObject, config) {
|
||||
if (!parseObject) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
var trigger = getTrigger(parseObject.className, triggerType, applicationId);
|
||||
var trigger = getTrigger(parseObject.className, triggerType, config.applicationId);
|
||||
if (!trigger) return resolve();
|
||||
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject);
|
||||
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config);
|
||||
var response = getResponseObject(request, resolve, reject);
|
||||
// Force the current Parse app before the trigger
|
||||
Parse.applicationId = applicationId;
|
||||
Parse.javascriptKey = cache.apps.get(applicationId).javascriptKey || '';
|
||||
Parse.masterKey = cache.apps.get(applicationId).masterKey;
|
||||
Parse.applicationId = config.applicationId;
|
||||
Parse.javascriptKey = config.javascriptKey || '';
|
||||
Parse.masterKey = config.masterKey;
|
||||
trigger(request, response);
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user