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
This commit is contained in:
Florent Vilmart
2016-08-12 13:25:24 -04:00
committed by Drew
parent 6e0a25dea0
commit a5a172918e
28 changed files with 396 additions and 293 deletions

View File

@@ -8,14 +8,13 @@
import { MongoClient, GridStore, Db} from 'mongodb';
import { FilesAdapter } from './FilesAdapter';
const DefaultMongoURI = 'mongodb://localhost:27017/parse';
import defaults from '../../defaults';
export class GridStoreAdapter extends FilesAdapter {
_databaseURI: string;
_connectionPromise: Promise<Db>;
constructor(mongoDatabaseURI = DefaultMongoURI) {
constructor(mongoDatabaseURI = defaults.DefaultMongoURI) {
super();
this._databaseURI = mongoDatabaseURI;
this._connect();

View File

@@ -3,15 +3,13 @@
// Allows you to change the logger mechanism
//
// Adapter classes must implement the following functions:
// * info(obj1 [, obj2, .., objN])
// * error(obj1 [, obj2, .., objN])
// * query(options, callback)
// * log() {}
// * query(options, callback) /* optional */
// Default is WinstonLoggerAdapter.js
export class LoggerAdapter {
info() {}
error() {}
query(options, callback) {}
constructor(options) {}
log(level, message, /* meta */) {}
}
export default LoggerAdapter;

View File

@@ -0,0 +1,100 @@
import winston from 'winston';
import fs from 'fs';
import path from 'path';
import DailyRotateFile from 'winston-daily-rotate-file';
import _ from 'lodash';
import defaults from '../../defaults';
const logger = new winston.Logger();
const additionalTransports = [];
function updateTransports(options) {
let transports = Object.assign({}, logger.transports);
if (options) {
let silent = options.silent;
delete options.silent;
if (_.isNull(options.dirname)) {
delete transports['parse-server'];
delete transports['parse-server-error'];
} else if (!_.isUndefined(options.dirname)) {
transports['parse-server'] = new (DailyRotateFile)(
Object.assign({
filename: 'parse-server.info',
name: 'parse-server',
}, options));
transports['parse-server-error'] = new (DailyRotateFile)(
Object.assign({
filename: 'parse-server.err',
name: 'parse-server-error',
level: 'error'
}, options));
}
transports.console = new (winston.transports.Console)(
Object.assign({
colorize: true,
name: 'console',
silent
}, options));
}
// Mount the additional transports
additionalTransports.forEach((transport) => {
transports[transport.name] = transport;
});
logger.configure({
transports: _.values(transports)
});
}
export function configureLogger({
logsFolder = defaults.logsFolder,
jsonLogs = defaults.jsonLogs,
logLevel = winston.level,
verbose = defaults.verbose,
silent = defaults.silent } = {}) {
if (verbose) {
logLevel = 'verbose';
}
winston.level = logLevel;
const options = {};
if (logsFolder) {
if (!path.isAbsolute(logsFolder)) {
logsFolder = path.resolve(process.cwd(), logsFolder);
}
try {
fs.mkdirSync(logsFolder);
} catch (exception) {}
}
options.dirname = logsFolder;
options.level = logLevel;
options.silent = silent;
if (jsonLogs) {
options.json = true;
options.stringify = true;
}
updateTransports(options);
}
export function addTransport(transport) {
additionalTransports.push(transport);
updateTransports();
}
export function removeTransport(transport) {
let transportName = typeof transport == 'string' ? transport : transport.name;
let transports = Object.assign({}, logger.transports);
delete transports[transportName];
logger.configure({
transports: _.values(transports)
});
_.remove(additionalTransports, (transport) => {
return transport.name === transportName;
});
}
export { logger, addTransport, configureLogger, removeTransport };
export default logger;

View File

@@ -1,63 +1,23 @@
import { LoggerAdapter } from './LoggerAdapter';
import { logger, addTransport } from '../../logger';
import { logger, addTransport, configureLogger } from './WinstonLogger';
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
const CACHE_TIME = 1000 * 60;
let currentDate = new Date();
let simpleCache = {
timestamp: null,
from: null,
until: null,
order: null,
data: [],
level: 'info',
};
// returns Date object rounded to nearest day
let _getNearestDay = (date) => {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
// returns Date object of previous day
let _getPrevDay = (date) => {
return new Date(date - MILLISECONDS_IN_A_DAY);
}
// returns the iso formatted file name
let _getFileName = () => {
return _getNearestDay(currentDate).toISOString()
}
// check for valid cache when both from and util match.
// cache valid for up to 1 minute
let _hasValidCache = (from, until, level) => {
if (String(from) === String(simpleCache.from) &&
String(until) === String(simpleCache.until) &&
new Date() - simpleCache.timestamp < CACHE_TIME &&
level === simpleCache.level) {
return true;
}
return false;
}
// check that log entry has valid time stamp based on query
let _isValidLogEntry = (from, until, entry) => {
var _entry = JSON.parse(entry),
timestamp = new Date(_entry.timestamp);
return timestamp >= from && timestamp <= until
? true
: false
};
export class WinstonLoggerAdapter extends LoggerAdapter {
info() {
return logger.info.apply(undefined, arguments);
constructor(options) {
super();
if (options) {
configureLogger(options);
}
}
error() {
return logger.error.apply(undefined, arguments);
log() {
return logger.log.apply(logger, arguments);
}
addTransport(transport) {

View File

@@ -17,7 +17,6 @@ let mongodb = require('mongodb');
let MongoClient = mongodb.MongoClient;
const MongoSchemaCollectionName = '_SCHEMA';
const DefaultMongoURI = 'mongodb://localhost:27017/parse';
const storageAdapterAllCollections = mongoAdapter => {
return mongoAdapter.connect()
@@ -86,7 +85,7 @@ export class MongoStorageAdapter {
database;
constructor({
uri = DefaultMongoURI,
uri = defaults.DefaultMongoURI,
collectionPrefix = '',
mongoOptions = {},
}) {