Skip to content

Commit 6e9529f

Browse files
blachaflovilmart
authored andcommitted
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
1 parent 2d94a88 commit 6e9529f

File tree

6 files changed

+87
-21
lines changed

6 files changed

+87
-21
lines changed

spec/CloudCodeLogger.spec.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
3+
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
4+
5+
describe("Cloud Code Logger", () => {
6+
7+
it("should expose log to functions", (done) => {
8+
var logController = new LoggerController(new FileLoggerAdapter());
9+
10+
Parse.Cloud.define("loggerTest", (req, res) => {
11+
req.log.info('logTest', 'info log', {info: 'some log' });
12+
req.log.error('logTest','error log', {error: 'there was an error'});
13+
res.success({});
14+
});
15+
16+
Parse.Cloud.run('loggerTest').then(() => {
17+
Parse.Cloud._removeHook('Functions', 'logTest');
18+
return logController.getLogs({from: Date.now() - 500, size: 1000});
19+
}).then((res) => {
20+
expect(res.length).not.toBe(0);
21+
let lastLogs = res.slice(0, 2);
22+
let errorMessage = lastLogs[0];
23+
let infoMessage = lastLogs[1];
24+
expect(errorMessage.level).toBe('error');
25+
expect(errorMessage.error).toBe('there was an error');
26+
expect(errorMessage.message).toBe('logTest error log');
27+
expect(infoMessage.level).toBe('info');
28+
expect(infoMessage.info).toBe('some log');
29+
expect(infoMessage.message).toBe('logTest info log');
30+
done();
31+
});
32+
});
33+
34+
it("should expose log to trigger", (done) => {
35+
var logController = new LoggerController(new FileLoggerAdapter());
36+
37+
Parse.Cloud.beforeSave("MyObject", (req, res) => {
38+
req.log.info('beforeSave MyObject', 'info log', {info: 'some log' });
39+
req.log.error('beforeSave MyObject','error log', {error: 'there was an error'});
40+
res.success({});
41+
});
42+
43+
let obj = new Parse.Object('MyObject');
44+
obj.save().then(() => {
45+
Parse.Cloud._removeHook('Triggers', 'beforeSave', 'MyObject');
46+
return logController.getLogs({from: Date.now() - 500, size: 1000})
47+
}).then((res) => {
48+
expect(res.length).not.toBe(0);
49+
let lastLogs = res.slice(0, 2);
50+
let errorMessage = lastLogs[0];
51+
let infoMessage = lastLogs[1];
52+
expect(errorMessage.level).toBe('error');
53+
expect(errorMessage.error).toBe('there was an error');
54+
expect(errorMessage.message).toBe('beforeSave MyObject error log');
55+
expect(infoMessage.level).toBe('info');
56+
expect(infoMessage.info).toBe('some log');
57+
expect(infoMessage.message).toBe('beforeSave MyObject info log');
58+
done();
59+
});
60+
});
61+
});

spec/FileLoggerAdapter.spec.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ describe('info logs', () => {
77
var fileLoggerAdapter = new FileLoggerAdapter();
88
fileLoggerAdapter.info('testing info logs', () => {
99
fileLoggerAdapter.query({
10-
size: 1,
10+
from: new Date(Date.now() - 500),
11+
size: 100,
1112
level: 'info'
1213
}, (results) => {
1314
if(results.length == 0) {
@@ -28,7 +29,8 @@ describe('error logs', () => {
2829
var fileLoggerAdapter = new FileLoggerAdapter();
2930
fileLoggerAdapter.error('testing error logs', () => {
3031
fileLoggerAdapter.query({
31-
size: 1,
32+
from: new Date(Date.now() - 500),
33+
size: 100,
3234
level: 'error'
3335
}, (results) => {
3436
if(results.length == 0) {

src/RestWrite.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ RestWrite.prototype.runBeforeTrigger = function() {
162162
updatedObject.set(this.sanitizedData());
163163

164164
return Promise.resolve().then(() => {
165-
return triggers.maybeRunTrigger(triggers.Types.beforeSave, this.auth, updatedObject, originalObject, this.config.applicationId);
165+
return triggers.maybeRunTrigger(triggers.Types.beforeSave, this.auth, updatedObject, originalObject, this.config);
166166
}).then((response) => {
167167
if (response && response.object) {
168168
this.data = response.object;
@@ -824,7 +824,7 @@ RestWrite.prototype.runAfterTrigger = function() {
824824
this.config.liveQueryController.onAfterSave(updatedObject.className, updatedObject, originalObject);
825825

826826
// Run afterSave trigger
827-
triggers.maybeRunTrigger(triggers.Types.afterSave, this.auth, updatedObject, originalObject, this.config.applicationId);
827+
triggers.maybeRunTrigger(triggers.Types.afterSave, this.auth, updatedObject, originalObject, this.config);
828828
};
829829

830830
// A helper to figure out what location this operation happens at.

src/Routers/FunctionsRouter.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ var express = require('express'),
77
import PromiseRouter from '../PromiseRouter';
88

99
export class FunctionsRouter extends PromiseRouter {
10-
10+
1111
mountRoutes() {
1212
this.route('POST', '/functions/:functionName', FunctionsRouter.handleCloudFunction);
1313
}
14-
14+
1515
static createResponseObject(resolve, reject) {
1616
return {
1717
success: function(result) {
@@ -26,19 +26,19 @@ export class FunctionsRouter extends PromiseRouter {
2626
}
2727
}
2828
}
29-
29+
3030
static handleCloudFunction(req) {
3131
var applicationId = req.config.applicationId;
3232
var theFunction = triggers.getFunction(req.params.functionName, applicationId);
3333
var theValidator = triggers.getValidator(req.params.functionName, applicationId);
3434
if (theFunction) {
35-
3635
const params = Object.assign({}, req.body, req.query);
3736
var request = {
3837
params: params,
3938
master: req.auth && req.auth.isMaster,
4039
user: req.auth && req.auth.user,
41-
installationId: req.info.installationId
40+
installationId: req.info.installationId,
41+
log: req.config.loggerController && req.config.loggerController.adapter
4242
};
4343

4444
if (theValidator && typeof theValidator === "function") {

src/rest.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function del(config, auth, className, objectId) {
5252
inflatedObject = Parse.Object.fromJSON(response.results[0]);
5353
// Notify LiveQuery server if possible
5454
config.liveQueryController.onAfterDelete(inflatedObject.className, inflatedObject);
55-
return triggers.maybeRunTrigger(triggers.Types.beforeDelete, auth, inflatedObject, null, config.applicationId);
55+
return triggers.maybeRunTrigger(triggers.Types.beforeDelete, auth, inflatedObject, null, config);
5656
}
5757
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
5858
'Object not found for delete.');
@@ -79,7 +79,7 @@ function del(config, auth, className, objectId) {
7979
objectId: objectId
8080
}, options);
8181
}).then(() => {
82-
triggers.maybeRunTrigger(triggers.Types.afterDelete, auth, inflatedObject, null, config.applicationId);
82+
triggers.maybeRunTrigger(triggers.Types.afterDelete, auth, inflatedObject, null, config);
8383
return Promise.resolve();
8484
});
8585
}

src/triggers.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const baseStore = function() {
1616
base[key] = {};
1717
return base;
1818
}, {});
19-
19+
2020
return Object.freeze({
2121
Functions,
2222
Validators,
@@ -63,7 +63,7 @@ export function getTrigger(className, triggerType, applicationId) {
6363
throw "Missing ApplicationID";
6464
}
6565
var manager = _triggerStore[applicationId]
66-
if (manager
66+
if (manager
6767
&& manager.Triggers
6868
&& manager.Triggers[triggerType]
6969
&& manager.Triggers[triggerType][className]) {
@@ -92,15 +92,18 @@ export function getValidator(functionName, applicationId) {
9292
return undefined;
9393
}
9494

95-
export function getRequestObject(triggerType, auth, parseObject, originalParseObject) {
95+
export function getRequestObject(triggerType, auth, parseObject, originalParseObject, config) {
9696
var request = {
9797
triggerName: triggerType,
9898
object: parseObject,
99-
master: false
99+
master: false,
100+
log: config.loggerController && config.loggerController.adapter
100101
};
102+
101103
if (originalParseObject) {
102104
request.original = originalParseObject;
103105
}
106+
104107
if (!auth) {
105108
return request;
106109
}
@@ -145,19 +148,19 @@ export function getResponseObject(request, resolve, reject) {
145148
// Resolves to an object, empty or containing an object key. A beforeSave
146149
// trigger will set the object key to the rest format object to save.
147150
// originalParseObject is optional, we only need that for befote/afterSave functions
148-
export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObject, applicationId) {
151+
export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObject, config) {
149152
if (!parseObject) {
150153
return Promise.resolve({});
151154
}
152155
return new Promise(function (resolve, reject) {
153-
var trigger = getTrigger(parseObject.className, triggerType, applicationId);
156+
var trigger = getTrigger(parseObject.className, triggerType, config.applicationId);
154157
if (!trigger) return resolve();
155-
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject);
158+
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config);
156159
var response = getResponseObject(request, resolve, reject);
157160
// Force the current Parse app before the trigger
158-
Parse.applicationId = applicationId;
159-
Parse.javascriptKey = cache.apps.get(applicationId).javascriptKey || '';
160-
Parse.masterKey = cache.apps.get(applicationId).masterKey;
161+
Parse.applicationId = config.applicationId;
162+
Parse.javascriptKey = config.javascriptKey || '';
163+
Parse.masterKey = config.masterKey;
161164
trigger(request, response);
162165
});
163166
};

0 commit comments

Comments
 (0)