Skip to content

Commit bc961d8

Browse files
committed
Log objects rather than JSON strings and option for single line logs
This reverts commit fcd914b.
1 parent a00d795 commit bc961d8

File tree

7 files changed

+66
-24
lines changed

7 files changed

+66
-24
lines changed

README.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ That's it! You are now running a standalone version of Parse Server on your mach
2828

2929
**Using a remote MongoDB?** Pass the `--databaseURI DATABASE_URI` parameter when starting `parse-server`. Learn more about configuring Parse Server [here](#configuration). For a full list of available options, run `parse-server --help`.
3030

31-
**Want logs to be in placed in other folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
32-
3331
### Saving your first object
3432

3533
Now that you're running Parse Server, it is time to save your first object. We'll use the [REST API](https://parse.com/docs/rest/guide), but you can easily do the same using any of the [Parse SDKs](https://parseplatform.github.io/#sdks). Run the following:
@@ -145,6 +143,20 @@ app.listen(1337, function() {
145143

146144
For a full list of available options, run `parse-server --help`.
147145

146+
## Logging
147+
148+
Parse Server will, by default, will log:
149+
* to the console
150+
* daily rotating files as new line delimited JSON
151+
152+
Logs are also be viewable in Parse Dashboard but it only displays the `messages` field of each log entry. For example, with VERBOSE set this will exclude `origin` on each request.
153+
154+
**Want to log each request and response?** Set the `VERBOSE` environment variable when starting `parse-server`. Usage :- `VERBOSE='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
155+
156+
**Want logs to be in placed in other folder?** Pass the `PARSE_SERVER_LOGS_FOLDER` environment variable when starting `parse-server`. Usage :- `PARSE_SERVER_LOGS_FOLDER='<path-to-logs-folder>' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
157+
158+
**Want each log to be on a single line?** Pass the `SHORT_LOGS` environment variable when starting `parse-server`. Usage :- `SHORT_LOGS='1' parse-server --appId APPLICATION_ID --masterKey MASTER_KEY`
159+
148160
# Documentation
149161

150162
The full documentation for Parse Server is available in the [wiki](https://github.com/ParsePlatform/parse-server/wiki). The [Parse Server guide](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide) is a good place to get started. If you're interested in developing for Parse Server, the [Development guide](https://github.com/ParsePlatform/parse-server/wiki/Development-Guide) will help you get set up.

spec/FileLoggerAdapter.spec.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe('verbose logs', () => {
6262
level: 'verbose'
6363
});
6464
}).then((results) => {
65-
expect(results[1].message.includes('"password": "********"')).toEqual(true);
65+
expect(results[1].body.password).toEqual("********");
6666
var headers = {
6767
'X-Parse-Application-Id': 'test',
6868
'X-Parse-REST-API-Key': 'rest'
@@ -77,7 +77,7 @@ describe('verbose logs', () => {
7777
size: 100,
7878
level: 'verbose'
7979
}).then((results) => {
80-
expect(results[1].message.includes('password=********')).toEqual(true);
80+
expect(results[1].url.includes('password=********')).toEqual(true);
8181
done();
8282
});
8383
});
@@ -95,7 +95,7 @@ describe('verbose logs', () => {
9595
level: 'verbose'
9696
});
9797
}).then((results) => {
98-
expect(results[1].message.includes('"password": "pw"')).toEqual(true);
98+
expect(results[1].body.password).toEqual("pw");
9999
done();
100100
});
101101
});

src/Config.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export class Config {
2323
}
2424

2525
this.applicationId = applicationId;
26+
this.shortLogs = cacheInfo.shortLogs;
2627
this.masterKey = cacheInfo.masterKey;
2728
this.clientKey = cacheInfo.clientKey;
2829
this.javascriptKey = cacheInfo.javascriptKey;

src/ParseServer.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ addParseCloud();
6161
// and delete
6262
// "loggerAdapter": a class like FileLoggerAdapter providing info, error,
6363
// and query
64+
// "shortLogs": single line log entries
6465
// "databaseURI": a uri like mongodb://localhost:27017/dbname to tell us
6566
// what database this Parse API connects to.
6667
// "cloud": relative location to cloud code to require, or a function
@@ -90,6 +91,7 @@ class ParseServer {
9091
filesAdapter,
9192
push,
9293
loggerAdapter,
94+
shortLogs,
9395
logsFolder,
9496
databaseURI,
9597
databaseOptions,
@@ -174,6 +176,7 @@ class ParseServer {
174176
const cacheController = new CacheController(cacheControllerAdapter, appId);
175177

176178
AppCache.put(appId, {
179+
appId,
177180
masterKey: masterKey,
178181
serverURL: serverURL,
179182
collectionPrefix: collectionPrefix,
@@ -200,6 +203,7 @@ class ParseServer {
200203
liveQueryController: liveQueryController,
201204
sessionLength: Number(sessionLength),
202205
expireInactiveSessions: expireInactiveSessions,
206+
shortLogs,
203207
revokeSessionOnPasswordReset
204208
});
205209

@@ -217,7 +221,7 @@ class ParseServer {
217221
return ParseServer.app(this.config);
218222
}
219223

220-
static app({maxUploadSize = '20mb'}) {
224+
static app({maxUploadSize = '20mb', appId}) {
221225
// This app serves the Parse API directly.
222226
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
223227
var api = express();
@@ -263,7 +267,7 @@ class ParseServer {
263267
return memo.concat(router.routes);
264268
}, []);
265269

266-
let appRouter = new PromiseRouter(routes);
270+
let appRouter = new PromiseRouter(routes, appId);
267271

268272
batch.mountOnto(appRouter);
269273

src/PromiseRouter.js

+36-15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// themselves use our routing information, without disturbing express
66
// components that external developers may be modifying.
77

8+
import AppCache from './cache';
89
import express from 'express';
910
import url from 'url';
1011
import log from './logger';
@@ -19,8 +20,9 @@ export default class PromiseRouter {
1920
// status: optional. the http status code. defaults to 200
2021
// response: a json object with the content of the response
2122
// location: optional. a location header
22-
constructor(routes = []) {
23+
constructor(routes = [], appId) {
2324
this.routes = routes;
25+
this.appId = appId;
2426
this.mountRoutes();
2527
}
2628

@@ -107,16 +109,16 @@ export default class PromiseRouter {
107109
for (var route of this.routes) {
108110
switch(route.method) {
109111
case 'POST':
110-
expressApp.post(route.path, makeExpressHandler(route.handler));
112+
expressApp.post(route.path, makeExpressHandler(this.appId, route.handler));
111113
break;
112114
case 'GET':
113-
expressApp.get(route.path, makeExpressHandler(route.handler));
115+
expressApp.get(route.path, makeExpressHandler(this.appId, route.handler));
114116
break;
115117
case 'PUT':
116-
expressApp.put(route.path, makeExpressHandler(route.handler));
118+
expressApp.put(route.path, makeExpressHandler(this.appId, route.handler));
117119
break;
118120
case 'DELETE':
119-
expressApp.delete(route.path, makeExpressHandler(route.handler));
121+
expressApp.delete(route.path, makeExpressHandler(this.appId, route.handler));
120122
break;
121123
default:
122124
throw 'unexpected code branch';
@@ -129,16 +131,16 @@ export default class PromiseRouter {
129131
for (var route of this.routes) {
130132
switch(route.method) {
131133
case 'POST':
132-
expressApp.post(route.path, makeExpressHandler(route.handler));
134+
expressApp.post(route.path, makeExpressHandler(this.appId, route.handler));
133135
break;
134136
case 'GET':
135-
expressApp.get(route.path, makeExpressHandler(route.handler));
137+
expressApp.get(route.path, makeExpressHandler(this.appId, route.handler));
136138
break;
137139
case 'PUT':
138-
expressApp.put(route.path, makeExpressHandler(route.handler));
140+
expressApp.put(route.path, makeExpressHandler(this.appId, route.handler));
139141
break;
140142
case 'DELETE':
141-
expressApp.delete(route.path, makeExpressHandler(route.handler));
143+
expressApp.delete(route.path, makeExpressHandler(this.appId, route.handler));
142144
break;
143145
default:
144146
throw 'unexpected code branch';
@@ -152,17 +154,36 @@ export default class PromiseRouter {
152154
// handler.
153155
// Express handlers should never throw; if a promise handler throws we
154156
// just treat it like it resolved to an error.
155-
function makeExpressHandler(promiseHandler) {
157+
function makeExpressHandler(appId, promiseHandler) {
158+
let config = AppCache.get(appId);
156159
return function(req, res, next) {
160+
var url = maskSensitiveUrl(req);
157161
try {
158-
log.verbose(req.method, maskSensitiveUrl(req), req.headers,
159-
JSON.stringify(maskSensitiveBody(req), null, 2));
162+
var jsonBody;
163+
if (config.shortLogs) {
164+
jsonBody = JSON.stringify(maskSensitiveBody(req));
165+
} else {
166+
jsonBody = JSON.stringify(maskSensitiveBody(req), null, 2);
167+
}
168+
log.verbose(`REQUEST for [${req.method}] ${url}: ${jsonBody}`, {
169+
method: req.method,
170+
url: url,
171+
headers: req.headers,
172+
body: maskSensitiveBody(req)
173+
});
160174
promiseHandler(req).then((result) => {
161175
if (!result.response && !result.location && !result.text) {
162176
log.error('the handler did not include a "response" or a "location" field');
163177
throw 'control should not get here';
164178
}
165-
log.verbose(JSON.stringify(result, null, 2));
179+
180+
var jsonResponse;
181+
if (config.shortLogs) {
182+
jsonResponse = JSON.stringify(result);
183+
} else {
184+
jsonResponse = JSON.stringify(result, null, 2);
185+
}
186+
log.verbose(`RESPONSE from [${req.method}] ${url}: ${jsonResponse}`, {result: result});
166187

167188
var status = result.status || 200;
168189
res.status(status);
@@ -186,11 +207,11 @@ function makeExpressHandler(promiseHandler) {
186207
}
187208
res.json(result.response);
188209
}, (e) => {
189-
log.verbose('error:', e);
210+
log.error(`Error generating response. ${e}`, {error: e});
190211
next(e);
191212
});
192213
} catch (e) {
193-
log.verbose('exception:', e);
214+
log.error(`Error handling request: ${e}`, {error: e});
194215
next(e);
195216
}
196217
}

src/cli/cli-definitions.js

+4
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ export default {
179179
env: "VERBOSE",
180180
help: "Set the logging to verbose"
181181
},
182+
"shortLogs": {
183+
env: "SHORT_LOGS",
184+
help: "Single line log entries"
185+
},
182186
"revokeSessionOnPasswordReset": {
183187
env: "PARSE_SERVER_REVOKE_SESSION_ON_PASSWORD_RESET",
184188
help: "When a user changes their password, either through the reset password email or while logged in, all sessions are revoked if this is true. Set to false if you don't want to revoke sessions.",

src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import winston from 'winston';
21
import ParseServer from './ParseServer';
2+
import logger from './logger';
33
import S3Adapter from 'parse-server-s3-adapter'
44
import FileSystemAdapter from 'parse-server-fs-adapter'
55
import TestUtils from './TestUtils';
@@ -16,4 +16,4 @@ _ParseServer.createLiveQueryServer = ParseServer.createLiveQueryServer;
1616
let GCSAdapter = useExternal('GCSAdapter', 'parse-server-gcs-adapter');
1717

1818
export default ParseServer;
19-
export { S3Adapter, GCSAdapter, FileSystemAdapter, TestUtils, _ParseServer as ParseServer };
19+
export { S3Adapter, GCSAdapter, FileSystemAdapter, TestUtils, _ParseServer as ParseServer, logger };

0 commit comments

Comments
 (0)