Skip to content

Commit a5a1729

Browse files
flovilmartdrew-gross
authored andcommitted
Refactor logging to provide common logger from LoggerAdapter (#2478)
* Refactor logging to provide common logger from LoggerAdapter Move logger logic de WinstonLoggerAdapter Further improvements in configuration Use logger instead of getLogger - Removes PLog module Reverts name changes nits * Adds additional logging levels as requirements * Adds tests for logging configuration * removes flaky test * investigate... * further investigation * Adds silent option to disable console output * Restores logs with VERBOSE in tests * Expose controller instead of adapter, reduces method requirements for adapter * Shuffles initializations around * Fix doc * Load cloudCode last to make sure the logger is available * Adds test to make sure we can load an adapter from npm module * extract defaults * Adds defaultMongoURI to defaults * fix defaults values * Proper error for PG failures * Disable flaky test
1 parent 6e0a25d commit a5a1729

28 files changed

+395
-292
lines changed

spec/AdapterLoader.spec.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ describe("AdapterLoader", ()=>{
4545
done();
4646
});
4747

48+
it("should instantiate an adapter from npm module", (done) => {
49+
var adapter = loadAdapter({
50+
module: 'parse-server-fs-adapter'
51+
});
52+
53+
expect(typeof adapter).toBe('object');
54+
expect(typeof adapter.createFile).toBe('function');
55+
expect(typeof adapter.deleteFile).toBe('function');
56+
expect(typeof adapter.getFileData).toBe('function');
57+
expect(typeof adapter.getFileLocation).toBe('function');
58+
done();
59+
});
60+
4861
it("should instantiate an adapter from function/Class", (done) => {
4962
var adapter = loadAdapter({
5063
adapter: FilesAdapter

spec/InstallationsRouter.spec.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var InstallationsRouter = require('../src/Routers/InstallationsRouter').Installa
55

66
var config = new Config('test');
77

8-
describe('InstallationsRouter', () => {
8+
describe_only_db(['mongo'])('InstallationsRouter', () => {
99
it('uses find condition from request.body', (done) => {
1010
var androidDeviceRequest = {
1111
'installationId': '12345678-abcd-abcd-abcd-123456789abc',
@@ -71,6 +71,9 @@ describe('InstallationsRouter', () => {
7171
var results = res.response.results;
7272
expect(results.length).toEqual(1);
7373
done();
74+
}).catch((err) => {
75+
fail(JSON.stringify(err));
76+
done();
7477
});
7578
});
7679

@@ -172,6 +175,9 @@ describe('InstallationsRouter', () => {
172175
expect(response.results.length).toEqual(0);
173176
expect(response.count).toEqual(2);
174177
done();
178+
}).catch((err) => {
179+
fail(JSON.stringify(err));
180+
done();
175181
});
176182
});
177183
});

spec/Logger.spec.js

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var logger = require('../src/logger');
1+
var logging = require('../src/Adapters/Logger/WinstonLogger');
22
var winston = require('winston');
33

44
class TestTransport extends winston.Transport {
@@ -9,10 +9,55 @@ class TestTransport extends winston.Transport {
99

1010
describe('Logger', () => {
1111
it('should add transport', () => {
12-
const testTransport = new (TestTransport)({});
12+
const testTransport = new (TestTransport)({
13+
name: 'test'
14+
});
1315
spyOn(testTransport, 'log');
14-
logger.addTransport(testTransport);
15-
logger.logger.info('hi');
16+
logging.addTransport(testTransport);
17+
expect(Object.keys(logging.logger.transports).length).toBe(4);
18+
logging.logger.info('hi');
1619
expect(testTransport.log).toHaveBeenCalled();
20+
logging.removeTransport(testTransport);
21+
expect(Object.keys(logging.logger.transports).length).toBe(3);
22+
});
23+
24+
it('should have files transports', (done) => {
25+
reconfigureServer().then(() => {
26+
let transports = logging.logger.transports;
27+
let transportKeys = Object.keys(transports);
28+
expect(transportKeys.length).toBe(3);
29+
done();
30+
});
31+
});
32+
33+
it('should disable files logs', (done) => {
34+
reconfigureServer({
35+
logsFolder: null
36+
}).then(() => {
37+
let transports = logging.logger.transports;
38+
let transportKeys = Object.keys(transports);
39+
expect(transportKeys.length).toBe(1);
40+
done();
41+
});
42+
});
43+
44+
it('should enable JSON logs', (done) => {
45+
// Force console transport
46+
reconfigureServer({
47+
logsFolder: null,
48+
jsonLogs: true,
49+
silent: false
50+
}).then(() => {
51+
let spy = spyOn(process.stdout, 'write');
52+
logging.logger.info('hi', {key: 'value'});
53+
expect(process.stdout.write).toHaveBeenCalled();
54+
var firstLog = process.stdout.write.calls.first().args[0];
55+
expect(firstLog).toEqual(JSON.stringify({key: 'value', level: 'info', message: 'hi' })+'\n');
56+
return reconfigureServer({
57+
jsonLogs: false
58+
});
59+
}).then(() => {
60+
done();
61+
});
1762
});
1863
});

spec/Subscription.spec.js

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
var Subscription = require('../src/LiveQuery/Subscription').Subscription;
2-
2+
let logger;
33
describe('Subscription', function() {
44

55
beforeEach(function() {
6-
var mockError = jasmine.createSpy('error');
7-
jasmine.mockLibrary('../src/LiveQuery/PLog', 'error', mockError);
6+
logger = require('../src/logger').logger;
7+
spyOn(logger, 'error').and.callThrough();
88
});
99

1010
it('can be initialized', function() {
@@ -62,17 +62,15 @@ describe('Subscription', function() {
6262
var subscription = new Subscription('className', { key : 'value' }, 'hash');
6363
subscription.deleteClientSubscription(1, 1);
6464

65-
var PLog =require('../src/LiveQuery/PLog');
66-
expect(PLog.error).toHaveBeenCalled();
65+
expect(logger.error).toHaveBeenCalled();
6766
});
6867

6968
it('can delete nonexistent request for one client', function() {
7069
var subscription = new Subscription('className', { key : 'value' }, 'hash');
7170
subscription.addClientSubscription(1, 1);
7271
subscription.deleteClientSubscription(1, 2);
7372

74-
var PLog =require('../src/LiveQuery/PLog');
75-
expect(PLog.error).toHaveBeenCalled();
73+
expect(logger.error).toHaveBeenCalled();
7674
expect(subscription.clientRequestIds.size).toBe(1);
7775
expect(subscription.clientRequestIds.get(1)).toEqual([1]);
7876
});
@@ -83,8 +81,7 @@ describe('Subscription', function() {
8381
subscription.addClientSubscription(1, 2);
8482
subscription.deleteClientSubscription(1, 2);
8583

86-
var PLog =require('../src/LiveQuery/PLog');
87-
expect(PLog.error).not.toHaveBeenCalled();
84+
expect(logger.error).not.toHaveBeenCalled();
8885
expect(subscription.clientRequestIds.size).toBe(1);
8986
expect(subscription.clientRequestIds.get(1)).toEqual([1]);
9087
});
@@ -96,8 +93,7 @@ describe('Subscription', function() {
9693
subscription.deleteClientSubscription(1, 1);
9794
subscription.deleteClientSubscription(1, 2);
9895

99-
var PLog =require('../src/LiveQuery/PLog');
100-
expect(PLog.error).not.toHaveBeenCalled();
96+
expect(logger.error).not.toHaveBeenCalled();
10197
expect(subscription.clientRequestIds.size).toBe(0);
10298
});
10399

@@ -111,13 +107,8 @@ describe('Subscription', function() {
111107
subscription.deleteClientSubscription(2, 1);
112108
subscription.deleteClientSubscription(2, 2);
113109

114-
var PLog =require('../src/LiveQuery/PLog');
115-
expect(PLog.error).not.toHaveBeenCalled();
110+
expect(logger.error).not.toHaveBeenCalled();
116111
expect(subscription.clientRequestIds.size).toBe(1);
117112
expect(subscription.clientRequestIds.get(1)).toEqual([1]);
118113
});
119-
120-
afterEach(function(){
121-
jasmine.restoreLibrary('../src/LiveQuery/PLog', 'error');
122-
});
123114
});

spec/WinstonLoggerAdapter.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe('info logs', () => {
88

99
it("Verify INFO logs", (done) => {
1010
var winstonLoggerAdapter = new WinstonLoggerAdapter();
11-
winstonLoggerAdapter.info('testing info logs', () => {
11+
winstonLoggerAdapter.log('info', 'testing info logs', () => {
1212
winstonLoggerAdapter.query({
1313
from: new Date(Date.now() - 500),
1414
size: 100,
@@ -29,7 +29,7 @@ describe('info logs', () => {
2929
describe('error logs', () => {
3030
it("Verify ERROR logs", (done) => {
3131
var winstonLoggerAdapter = new WinstonLoggerAdapter();
32-
winstonLoggerAdapter.error('testing error logs', () => {
32+
winstonLoggerAdapter.log('error', 'testing error logs', () => {
3333
winstonLoggerAdapter.query({
3434
from: new Date(Date.now() - 500),
3535
size: 100,

spec/helper.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var defaultConfiguration = {
4545
webhookKey: 'hook',
4646
masterKey: 'test',
4747
fileKey: 'test',
48+
silent: !process.env.VERBOSE,
4849
push: {
4950
'ios': {
5051
cert: 'prodCert.pem',
@@ -352,8 +353,6 @@ global.describe_only_db = db => {
352353
}
353354
}
354355

355-
// LiveQuery test setting
356-
require('../src/LiveQuery/PLog').logLevel = 'NONE';
357356
var libraryCache = {};
358357
jasmine.mockLibrary = function(library, name, mock) {
359358
var original = require(library)[name];

src/Adapters/Files/GridStoreAdapter.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88

99
import { MongoClient, GridStore, Db} from 'mongodb';
1010
import { FilesAdapter } from './FilesAdapter';
11-
12-
const DefaultMongoURI = 'mongodb://localhost:27017/parse';
11+
import defaults from '../../defaults';
1312

1413
export class GridStoreAdapter extends FilesAdapter {
1514
_databaseURI: string;
1615
_connectionPromise: Promise<Db>;
1716

18-
constructor(mongoDatabaseURI = DefaultMongoURI) {
17+
constructor(mongoDatabaseURI = defaults.DefaultMongoURI) {
1918
super();
2019
this._databaseURI = mongoDatabaseURI;
2120
this._connect();

src/Adapters/Logger/LoggerAdapter.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
// Allows you to change the logger mechanism
44
//
55
// Adapter classes must implement the following functions:
6-
// * info(obj1 [, obj2, .., objN])
7-
// * error(obj1 [, obj2, .., objN])
8-
// * query(options, callback)
6+
// * log() {}
7+
// * query(options, callback) /* optional */
98
// Default is WinstonLoggerAdapter.js
109

1110
export class LoggerAdapter {
12-
info() {}
13-
error() {}
14-
query(options, callback) {}
11+
constructor(options) {}
12+
log(level, message, /* meta */) {}
1513
}
1614

1715
export default LoggerAdapter;

src/Adapters/Logger/WinstonLogger.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import winston from 'winston';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import DailyRotateFile from 'winston-daily-rotate-file';
5+
import _ from 'lodash';
6+
import defaults from '../../defaults';
7+
8+
const logger = new winston.Logger();
9+
const additionalTransports = [];
10+
11+
function updateTransports(options) {
12+
let transports = Object.assign({}, logger.transports);
13+
if (options) {
14+
let silent = options.silent;
15+
delete options.silent;
16+
if (_.isNull(options.dirname)) {
17+
delete transports['parse-server'];
18+
delete transports['parse-server-error'];
19+
} else if (!_.isUndefined(options.dirname)) {
20+
transports['parse-server'] = new (DailyRotateFile)(
21+
Object.assign({
22+
filename: 'parse-server.info',
23+
name: 'parse-server',
24+
}, options));
25+
transports['parse-server-error'] = new (DailyRotateFile)(
26+
Object.assign({
27+
filename: 'parse-server.err',
28+
name: 'parse-server-error',
29+
level: 'error'
30+
}, options));
31+
}
32+
33+
transports.console = new (winston.transports.Console)(
34+
Object.assign({
35+
colorize: true,
36+
name: 'console',
37+
silent
38+
}, options));
39+
}
40+
// Mount the additional transports
41+
additionalTransports.forEach((transport) => {
42+
transports[transport.name] = transport;
43+
});
44+
logger.configure({
45+
transports: _.values(transports)
46+
});
47+
}
48+
49+
export function configureLogger({
50+
logsFolder = defaults.logsFolder,
51+
jsonLogs = defaults.jsonLogs,
52+
logLevel = winston.level,
53+
verbose = defaults.verbose,
54+
silent = defaults.silent } = {}) {
55+
56+
if (verbose) {
57+
logLevel = 'verbose';
58+
}
59+
60+
winston.level = logLevel;
61+
const options = {};
62+
63+
if (logsFolder) {
64+
if (!path.isAbsolute(logsFolder)) {
65+
logsFolder = path.resolve(process.cwd(), logsFolder);
66+
}
67+
try {
68+
fs.mkdirSync(logsFolder);
69+
} catch (exception) {}
70+
}
71+
options.dirname = logsFolder;
72+
options.level = logLevel;
73+
options.silent = silent;
74+
75+
if (jsonLogs) {
76+
options.json = true;
77+
options.stringify = true;
78+
}
79+
updateTransports(options);
80+
}
81+
82+
export function addTransport(transport) {
83+
additionalTransports.push(transport);
84+
updateTransports();
85+
}
86+
87+
export function removeTransport(transport) {
88+
let transportName = typeof transport == 'string' ? transport : transport.name;
89+
let transports = Object.assign({}, logger.transports);
90+
delete transports[transportName];
91+
logger.configure({
92+
transports: _.values(transports)
93+
});
94+
_.remove(additionalTransports, (transport) => {
95+
return transport.name === transportName;
96+
});
97+
}
98+
99+
export { logger, addTransport, configureLogger, removeTransport };
100+
export default logger;

0 commit comments

Comments
 (0)