Skip to content

Commit ef08dcf

Browse files
committed
Merge pull request #1234 from ParsePlatform/flovilmart.winston
Better logging with winston
2 parents 9dd8609 + 247a06f commit ef08dcf

15 files changed

+180
-255
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Logs
22
logs
3+
test_logs
34
*.log
45

56
# Runtime data

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"request": "^2.65.0",
4242
"tv4": "^1.2.7",
4343
"winston": "^2.1.1",
44+
"winston-daily-rotate-file": "^1.0.1",
4445
"ws": "^1.0.1"
4546
},
4647
"devDependencies": {

spec/FileLoggerAdapter.spec.js

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,10 @@
11
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
22
var Parse = require('parse/node').Parse;
3-
var request = require('request');
4-
var fs = require('fs');
5-
6-
var LOGS_FOLDER = './test_logs/';
7-
8-
var deleteFolderRecursive = function(path) {
9-
if( fs.existsSync(path) ) {
10-
fs.readdirSync(path).forEach(function(file,index){
11-
var curPath = path + "/" + file;
12-
if(fs.lstatSync(curPath).isDirectory()) { // recurse
13-
deleteFolderRecursive(curPath);
14-
} else { // delete file
15-
fs.unlinkSync(curPath);
16-
}
17-
});
18-
fs.rmdirSync(path);
19-
}
20-
};
213

224
describe('info logs', () => {
235

24-
afterEach((done) => {
25-
deleteFolderRecursive(LOGS_FOLDER);
26-
done();
27-
});
28-
296
it("Verify INFO logs", (done) => {
30-
var fileLoggerAdapter = new FileLoggerAdapter({
31-
logsFolder: LOGS_FOLDER
32-
});
7+
var fileLoggerAdapter = new FileLoggerAdapter();
338
fileLoggerAdapter.info('testing info logs', () => {
349
fileLoggerAdapter.query({
3510
size: 1,
@@ -49,11 +24,6 @@ describe('info logs', () => {
4924

5025
describe('error logs', () => {
5126

52-
afterEach((done) => {
53-
deleteFolderRecursive(LOGS_FOLDER);
54-
done();
55-
});
56-
5727
it("Verify ERROR logs", (done) => {
5828
var fileLoggerAdapter = new FileLoggerAdapter();
5929
fileLoggerAdapter.error('testing error logs', () => {

spec/LoggerController.spec.js

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,40 @@ describe('LoggerController', () => {
1010

1111
expect(() => {
1212
loggerController.getLogs(query).then(function(res) {
13-
expect(res.length).toBe(0);
13+
expect(res.length).not.toBe(0);
14+
done();
15+
}).catch((err) => {
16+
console.error(err);
17+
fail("should not fail");
1418
done();
1519
})
1620
}).not.toThrow();
1721
});
18-
22+
1923
it('properly validates dateTimes', (done) => {
2024
expect(LoggerController.validDateTime()).toBe(null);
2125
expect(LoggerController.validDateTime("String")).toBe(null);
2226
expect(LoggerController.validDateTime(123456).getTime()).toBe(123456);
2327
expect(LoggerController.validDateTime("2016-01-01Z00:00:00").getTime()).toBe(1451606400000);
2428
done();
2529
});
26-
30+
2731
it('can set the proper default values', (done) => {
2832
// Make mock request
2933
var result = LoggerController.parseOptions();
3034
expect(result.size).toEqual(10);
3135
expect(result.order).toEqual('desc');
3236
expect(result.level).toEqual('info');
33-
37+
3438
done();
3539
});
36-
40+
3741
it('can process a query witout throwing', (done) => {
3842
// Make mock request
3943
var query = {
4044
from: "2016-01-01Z00:00:00",
4145
until: "2016-01-01Z00:00:00",
42-
size: 5,
46+
size: 5,
4347
order: 'asc',
4448
level: 'error'
4549
};
@@ -51,16 +55,16 @@ describe('LoggerController', () => {
5155
expect(result.size).toEqual(5);
5256
expect(result.order).toEqual('asc');
5357
expect(result.level).toEqual('error');
54-
58+
5559
done();
5660
});
57-
61+
5862
it('can check process a query witout throwing', (done) => {
5963
// Make mock request
6064
var query = {
61-
from: "2015-01-01",
62-
until: "2016-01-01",
63-
size: 5,
65+
from: "2016-01-01",
66+
until: "2016-01-30",
67+
size: 5,
6468
order: 'desc',
6569
level: 'error'
6670
};
@@ -71,13 +75,15 @@ describe('LoggerController', () => {
7175
loggerController.getLogs(query).then(function(res) {
7276
expect(res.length).toBe(0);
7377
done();
78+
}).catch((err) => {
79+
console.error(err);
80+
fail("should not fail");
81+
done();
7482
})
7583
}).not.toThrow();
7684
});
77-
78-
it('should throw without an adapter', (done) => {
79-
8085

86+
it('should throw without an adapter', (done) => {
8187
expect(() => {
8288
var loggerController = new LoggerController();
8389
}).toThrow();

src/Adapters/Logger/FileLoggerAdapter.js

Lines changed: 24 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// Logger
22
//
33
// Wrapper around Winston logging library with custom query
4-
//
4+
//
55
// expected log entry to be in the shape of:
66
// {"level":"info","message":"Your Message","timestamp":"2016-02-04T05:59:27.412Z"}
77
//
88
import { LoggerAdapter } from './LoggerAdapter';
99
import winston from 'winston';
1010
import fs from 'fs';
1111
import { Parse } from 'parse/node';
12+
import { logger, configure } from '../../logger';
1213

1314
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
1415
const CACHE_TIME = 1000 * 60;
@@ -57,24 +58,6 @@ let _hasValidCache = (from, until, level) => {
5758
return false;
5859
}
5960

60-
// renews transports to current date
61-
let _renewTransports = ({infoLogger, errorLogger, logsFolder}) => {
62-
if (infoLogger) {
63-
infoLogger.add(winston.transports.File, {
64-
filename: logsFolder + _getFileName() + '.info',
65-
name: 'info-file',
66-
level: 'info'
67-
});
68-
}
69-
if (errorLogger) {
70-
errorLogger.add(winston.transports.File, {
71-
filename: logsFolder + _getFileName() + '.error',
72-
name: 'error-file',
73-
level: 'error'
74-
});
75-
}
76-
};
77-
7861
// check that log entry has valid time stamp based on query
7962
let _isValidLogEntry = (from, until, entry) => {
8063
var _entry = JSON.parse(entry),
@@ -84,139 +67,51 @@ let _isValidLogEntry = (from, until, entry) => {
8467
: false
8568
};
8669

87-
// ensure that file name is up to date
88-
let _verifyTransports = ({infoLogger, errorLogger, logsFolder}) => {
89-
if (_getNearestDay(currentDate) !== _getNearestDay(new Date())) {
90-
currentDate = new Date();
91-
if (infoLogger) {
92-
infoLogger.remove('info-file');
93-
}
94-
if (errorLogger) {
95-
errorLogger.remove('error-file');
96-
}
97-
_renewTransports({infoLogger, errorLogger, logsFolder});
98-
}
99-
}
100-
10170
export class FileLoggerAdapter extends LoggerAdapter {
102-
constructor(options = {}) {
103-
super();
104-
this._logsFolder = options.logsFolder || LOGS_FOLDER;
105-
106-
// check logs folder exists
107-
if (!fs.existsSync(this._logsFolder)) {
108-
fs.mkdirSync(this._logsFolder);
109-
}
110-
111-
this._errorLogger = new (winston.Logger)({
112-
exitOnError: false,
113-
transports: [
114-
new (winston.transports.File)({
115-
filename: this._logsFolder + _getFileName() + '.error',
116-
name: 'error-file',
117-
level: 'error'
118-
})
119-
]
120-
});
121-
122-
this._infoLogger = new (winston.Logger)({
123-
exitOnError: false,
124-
transports: [
125-
new (winston.transports.File)({
126-
filename: this._logsFolder + _getFileName() + '.info',
127-
name: 'info-file',
128-
level: 'info'
129-
})
130-
]
131-
});
132-
}
13371

13472
info() {
135-
_verifyTransports({infoLogger: this._infoLogger, logsFolder: this._logsFolder});
136-
return this._infoLogger.info.apply(undefined, arguments);
73+
return logger.info.apply(undefined, arguments);
13774
}
13875

13976
error() {
140-
_verifyTransports({errorLogger: this._errorLogger, logsFolder: this._logsFolder});
141-
return this._errorLogger.error.apply(undefined, arguments);
77+
return logger.error.apply(undefined, arguments);
14278
}
14379

14480
// custom query as winston is currently limited
145-
query(options, callback) {
81+
query(options, callback = () => {}) {
14682
if (!options) {
14783
options = {};
14884
}
14985
// defaults to 7 days prior
15086
let from = options.from || new Date(Date.now() - (7 * MILLISECONDS_IN_A_DAY));
15187
let until = options.until || new Date();
152-
let size = options.size || 10;
88+
let limit = options.size || 10;
15389
let order = options.order || 'desc';
15490
let level = options.level || 'info';
15591
let roundedUntil = _getNearestDay(until);
15692
let roundedFrom = _getNearestDay(from);
15793

158-
if (_hasValidCache(roundedFrom, roundedUntil, level)) {
159-
let logs = [];
160-
if (order !== simpleCache.order) {
161-
// reverse order of data
162-
simpleCache.data.forEach((entry) => {
163-
logs.unshift(entry);
164-
});
165-
} else {
166-
logs = simpleCache.data;
167-
}
168-
callback(logs.slice(0, size));
169-
return;
170-
}
171-
172-
let curDate = roundedUntil;
173-
let curSize = 0;
174-
let method = order === 'desc' ? 'push' : 'unshift';
175-
let files = [];
176-
let promises = [];
177-
178-
// current a batch call, all files with valid dates are read
179-
while (curDate >= from) {
180-
files[method](this._logsFolder + curDate.toISOString() + '.' + level);
181-
curDate = _getPrevDay(curDate);
182-
}
94+
var options = {
95+
from,
96+
until,
97+
limit,
98+
order
99+
};
183100

184-
// read each file and split based on newline char.
185-
// limitation is message cannot contain newline
186-
// TODO: strip out delimiter from logged message
187-
files.forEach(function(file, i) {
188-
let promise = new Parse.Promise();
189-
fs.readFile(file, 'utf8', function(err, data) {
101+
return new Promise((resolve, reject) => {
102+
logger.query(options, (err, res) => {
190103
if (err) {
191-
promise.resolve([]);
192-
} else {
193-
let results = data.split('\n').filter((value) => {
194-
return value.trim() !== '';
195-
});
196-
promise.resolve(results);
104+
callback(err);
105+
return reject(err);
197106
}
198-
});
199-
promises[method](promise);
200-
});
201-
202-
Parse.Promise.when(promises).then((results) => {
203-
let logs = [];
204-
results.forEach(function(logEntries, i) {
205-
logEntries.forEach(function(entry) {
206-
if (_isValidLogEntry(from, until, entry)) {
207-
logs[method](JSON.parse(entry));
208-
}
209-
});
210-
});
211-
simpleCache = {
212-
timestamp: new Date(),
213-
from: roundedFrom,
214-
until: roundedUntil,
215-
data: logs,
216-
order,
217-
level,
218-
};
219-
callback(logs.slice(0, size));
107+
if (level == 'error') {
108+
callback(res['parse-server-error']);
109+
resolve(res['parse-server-error']);
110+
} else {
111+
callback(res['parse-server']);
112+
resolve(res['parse-server']);
113+
}
114+
})
220115
});
221116
}
222117
}

0 commit comments

Comments
 (0)