Allow logger to add transports (#2363)
- Move all of the winston logic from FileLoggerAdapter to WinstonLoggerAdapter - Export WinstonLoggerAdapter so it can be sublcassed - Expost the ability to add adittional transports to logger - Import FirehoseLoggerAdapter alongside other adapters so it can be configured.
This commit is contained in:
committed by
Florent Vilmart
parent
36891f4ed7
commit
fa736f1df7
@@ -1,10 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
||||||
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
var WinstonLoggerAdapter = require('../src/Adapters/Logger/WinstonLoggerAdapter').WinstonLoggerAdapter;
|
||||||
|
|
||||||
describe("Cloud Code Logger", () => {
|
describe("Cloud Code Logger", () => {
|
||||||
it("should expose log to functions", (done) => {
|
it("should expose log to functions", (done) => {
|
||||||
var logController = new LoggerController(new FileLoggerAdapter());
|
var logController = new LoggerController(new WinstonLoggerAdapter());
|
||||||
|
|
||||||
Parse.Cloud.define("loggerTest", (req, res) => {
|
Parse.Cloud.define("loggerTest", (req, res) => {
|
||||||
req.log.info('logTest', 'info log', {info: 'some log' });
|
req.log.info('logTest', 'info log', {info: 'some log' });
|
||||||
@@ -35,7 +35,7 @@ describe("Cloud Code Logger", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should expose log to trigger", (done) => {
|
it("should expose log to trigger", (done) => {
|
||||||
var logController = new LoggerController(new FileLoggerAdapter());
|
var logController = new LoggerController(new WinstonLoggerAdapter());
|
||||||
|
|
||||||
Parse.Cloud.beforeSave("MyObject", (req, res) => {
|
Parse.Cloud.beforeSave("MyObject", (req, res) => {
|
||||||
req.log.info('beforeSave MyObject', 'info log', {info: 'some log' });
|
req.log.info('beforeSave MyObject', 'info log', {info: 'some log' });
|
||||||
|
|||||||
18
spec/Logger.spec.js
Normal file
18
spec/Logger.spec.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
var logger = require('../src/logger');
|
||||||
|
var winston = require('winston');
|
||||||
|
|
||||||
|
class TestTransport extends winston.Transport {
|
||||||
|
log(level, msg, meta, callback) {
|
||||||
|
callback(null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Logger', () => {
|
||||||
|
it('should add transport', () => {
|
||||||
|
const testTransport = new (TestTransport)({});
|
||||||
|
spyOn(testTransport, 'log');
|
||||||
|
logger.addTransport(testTransport);
|
||||||
|
logger.logger.info('hi');
|
||||||
|
expect(testTransport.log).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
||||||
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
var WinstonLoggerAdapter = require('../src/Adapters/Logger/WinstonLoggerAdapter').WinstonLoggerAdapter;
|
||||||
|
|
||||||
describe('LoggerController', () => {
|
describe('LoggerController', () => {
|
||||||
it('can check process a query without throwing', (done) => {
|
it('can check process a query without throwing', (done) => {
|
||||||
// Make mock request
|
// Make mock request
|
||||||
var query = {};
|
var query = {};
|
||||||
|
|
||||||
var loggerController = new LoggerController(new FileLoggerAdapter());
|
var loggerController = new LoggerController(new WinstonLoggerAdapter());
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
loggerController.getLogs(query).then(function(res) {
|
loggerController.getLogs(query).then(function(res) {
|
||||||
@@ -69,7 +69,7 @@ describe('LoggerController', () => {
|
|||||||
level: 'error'
|
level: 'error'
|
||||||
};
|
};
|
||||||
|
|
||||||
var loggerController = new LoggerController(new FileLoggerAdapter());
|
var loggerController = new LoggerController(new WinstonLoggerAdapter());
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
loggerController.getLogs(query).then(function(res) {
|
loggerController.getLogs(query).then(function(res) {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
const request = require('request');
|
const request = require('request');
|
||||||
var LogsRouter = require('../src/Routers/LogsRouter').LogsRouter;
|
var LogsRouter = require('../src/Routers/LogsRouter').LogsRouter;
|
||||||
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
|
||||||
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
var WinstonLoggerAdapter = require('../src/Adapters/Logger/WinstonLoggerAdapter').WinstonLoggerAdapter;
|
||||||
|
|
||||||
const loggerController = new LoggerController(new FileLoggerAdapter());
|
const loggerController = new LoggerController(new WinstonLoggerAdapter());
|
||||||
|
|
||||||
describe('LogsRouter', () => {
|
describe('LogsRouter', () => {
|
||||||
it('can check valid master key of request', (done) => {
|
it('can check valid master key of request', (done) => {
|
||||||
|
|||||||
@@ -1,35 +1,36 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
|
var WinstonLoggerAdapter = require('../src/Adapters/Logger/WinstonLoggerAdapter').WinstonLoggerAdapter;
|
||||||
var Parse = require('parse/node').Parse;
|
var Parse = require('parse/node').Parse;
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
|
|
||||||
describe('info logs', () => {
|
describe('info logs', () => {
|
||||||
|
|
||||||
it("Verify INFO logs", (done) => {
|
it("Verify INFO logs", (done) => {
|
||||||
var fileLoggerAdapter = new FileLoggerAdapter();
|
var winstonLoggerAdapter = new WinstonLoggerAdapter();
|
||||||
fileLoggerAdapter.info('testing info logs', () => {
|
winstonLoggerAdapter.info('testing info logs', () => {
|
||||||
fileLoggerAdapter.query({
|
winstonLoggerAdapter.query({
|
||||||
from: new Date(Date.now() - 500),
|
from: new Date(Date.now() - 500),
|
||||||
size: 100,
|
size: 100,
|
||||||
level: 'info'
|
level: 'info'
|
||||||
}, (results) => {
|
}, (results) => {
|
||||||
if(results.length == 0) {
|
if (results.length == 0) {
|
||||||
fail('The adapter should return non-empty results');
|
fail('The adapter should return non-empty results');
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
expect(results[0].message).toEqual('testing info logs');
|
expect(results[0].message).toEqual('testing info logs');
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('error logs', () => {
|
describe('error logs', () => {
|
||||||
it("Verify ERROR logs", (done) => {
|
it("Verify ERROR logs", (done) => {
|
||||||
var fileLoggerAdapter = new FileLoggerAdapter();
|
var winstonLoggerAdapter = new WinstonLoggerAdapter();
|
||||||
fileLoggerAdapter.error('testing error logs', () => {
|
winstonLoggerAdapter.error('testing error logs', () => {
|
||||||
fileLoggerAdapter.query({
|
winstonLoggerAdapter.query({
|
||||||
from: new Date(Date.now() - 500),
|
from: new Date(Date.now() - 500),
|
||||||
size: 100,
|
size: 100,
|
||||||
level: 'error'
|
level: 'error'
|
||||||
@@ -52,8 +53,8 @@ describe('verbose logs', () => {
|
|||||||
reconfigureServer({ verbose: true })
|
reconfigureServer({ verbose: true })
|
||||||
.then(() => createTestUser())
|
.then(() => createTestUser())
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let fileLoggerAdapter = new FileLoggerAdapter();
|
let winstonLoggerAdapter = new WinstonLoggerAdapter();
|
||||||
return fileLoggerAdapter.query({
|
return winstonLoggerAdapter.query({
|
||||||
from: new Date(Date.now() - 500),
|
from: new Date(Date.now() - 500),
|
||||||
size: 100,
|
size: 100,
|
||||||
level: 'verbose'
|
level: 'verbose'
|
||||||
@@ -71,8 +72,8 @@ describe('verbose logs', () => {
|
|||||||
headers: headers,
|
headers: headers,
|
||||||
url: 'http://localhost:8378/1/login?username=test&password=moon-y'
|
url: 'http://localhost:8378/1/login?username=test&password=moon-y'
|
||||||
}, (error, response, body) => {
|
}, (error, response, body) => {
|
||||||
let fileLoggerAdapter = new FileLoggerAdapter();
|
let winstonLoggerAdapter = new WinstonLoggerAdapter();
|
||||||
return fileLoggerAdapter.query({
|
return winstonLoggerAdapter.query({
|
||||||
from: new Date(Date.now() - 500),
|
from: new Date(Date.now() - 500),
|
||||||
size: 100,
|
size: 100,
|
||||||
level: 'verbose'
|
level: 'verbose'
|
||||||
@@ -93,8 +94,8 @@ describe('verbose logs', () => {
|
|||||||
let obj = new Parse.Object('users');
|
let obj = new Parse.Object('users');
|
||||||
obj.set('password', 'pw');
|
obj.set('password', 'pw');
|
||||||
obj.save().then(() => {
|
obj.save().then(() => {
|
||||||
let fileLoggerAdapter = new FileLoggerAdapter();
|
let winstonLoggerAdapter = new WinstonLoggerAdapter();
|
||||||
return fileLoggerAdapter.query({
|
return winstonLoggerAdapter.query({
|
||||||
from: new Date(Date.now() - 500),
|
from: new Date(Date.now() - 500),
|
||||||
size: 100,
|
size: 100,
|
||||||
level: 'verbose'
|
level: 'verbose'
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
// * info(obj1 [, obj2, .., objN])
|
// * info(obj1 [, obj2, .., objN])
|
||||||
// * error(obj1 [, obj2, .., objN])
|
// * error(obj1 [, obj2, .., objN])
|
||||||
// * query(options, callback)
|
// * query(options, callback)
|
||||||
// Default is FileLoggerAdapter.js
|
// Default is WinstonLoggerAdapter.js
|
||||||
|
|
||||||
export class LoggerAdapter {
|
export class LoggerAdapter {
|
||||||
info() {}
|
info() {}
|
||||||
|
|||||||
@@ -1,23 +1,9 @@
|
|||||||
// Logger
|
|
||||||
//
|
|
||||||
// Wrapper around Winston logging library with custom query
|
|
||||||
//
|
|
||||||
// expected log entry to be in the shape of:
|
|
||||||
// {"level":"info","message":"Your Message","timestamp":"2016-02-04T05:59:27.412Z"}
|
|
||||||
//
|
|
||||||
import { LoggerAdapter } from './LoggerAdapter';
|
import { LoggerAdapter } from './LoggerAdapter';
|
||||||
import { Parse } from 'parse/node';
|
import { logger, addTransport } from '../../logger';
|
||||||
import { logger, configure } from '../../logger';
|
|
||||||
|
|
||||||
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
|
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000;
|
||||||
const CACHE_TIME = 1000 * 60;
|
const CACHE_TIME = 1000 * 60;
|
||||||
|
|
||||||
let LOGS_FOLDER = './logs/';
|
|
||||||
|
|
||||||
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
|
|
||||||
LOGS_FOLDER = './test_logs/'
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentDate = new Date();
|
let currentDate = new Date();
|
||||||
|
|
||||||
let simpleCache = {
|
let simpleCache = {
|
||||||
@@ -65,8 +51,7 @@ let _isValidLogEntry = (from, until, entry) => {
|
|||||||
: false
|
: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FileLoggerAdapter extends LoggerAdapter {
|
export class WinstonLoggerAdapter extends LoggerAdapter {
|
||||||
|
|
||||||
info() {
|
info() {
|
||||||
return logger.info.apply(undefined, arguments);
|
return logger.info.apply(undefined, arguments);
|
||||||
}
|
}
|
||||||
@@ -75,6 +60,13 @@ export class FileLoggerAdapter extends LoggerAdapter {
|
|||||||
return logger.error.apply(undefined, arguments);
|
return logger.error.apply(undefined, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addTransport(transport) {
|
||||||
|
// Note that this is calling addTransport
|
||||||
|
// from logger. See import - confusing.
|
||||||
|
// but this is not recursive.
|
||||||
|
addTransport(transport);
|
||||||
|
}
|
||||||
|
|
||||||
// custom query as winston is currently limited
|
// custom query as winston is currently limited
|
||||||
query(options, callback = () => {}) {
|
query(options, callback = () => {}) {
|
||||||
if (!options) {
|
if (!options) {
|
||||||
@@ -114,4 +106,4 @@ export class FileLoggerAdapter extends LoggerAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FileLoggerAdapter;
|
export default WinstonLoggerAdapter;
|
||||||
@@ -28,7 +28,7 @@ import { InMemoryCacheAdapter } from './Adapters/Cache/InMemoryCacheAdapter';
|
|||||||
import { AnalyticsController } from './Controllers/AnalyticsController';
|
import { AnalyticsController } from './Controllers/AnalyticsController';
|
||||||
import { CacheController } from './Controllers/CacheController';
|
import { CacheController } from './Controllers/CacheController';
|
||||||
import { AnalyticsAdapter } from './Adapters/Analytics/AnalyticsAdapter';
|
import { AnalyticsAdapter } from './Adapters/Analytics/AnalyticsAdapter';
|
||||||
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
|
import { WinstonLoggerAdapter } from './Adapters/Logger/WinstonLoggerAdapter';
|
||||||
import { FilesController } from './Controllers/FilesController';
|
import { FilesController } from './Controllers/FilesController';
|
||||||
import { FilesRouter } from './Routers/FilesRouter';
|
import { FilesRouter } from './Routers/FilesRouter';
|
||||||
import { FunctionsRouter } from './Routers/FunctionsRouter';
|
import { FunctionsRouter } from './Routers/FunctionsRouter';
|
||||||
@@ -71,7 +71,7 @@ const requiredUserFields = { fields: { ...SchemaController.defaultColumns._Defau
|
|||||||
// "analyticsAdapter": an adapter class for analytics
|
// "analyticsAdapter": an adapter class for analytics
|
||||||
// "filesAdapter": a class like GridStoreAdapter providing create, get,
|
// "filesAdapter": a class like GridStoreAdapter providing create, get,
|
||||||
// and delete
|
// and delete
|
||||||
// "loggerAdapter": a class like FileLoggerAdapter providing info, error,
|
// "loggerAdapter": a class like WinstonLoggerAdapter providing info, error,
|
||||||
// and query
|
// and query
|
||||||
// "jsonLogs": log as structured JSON objects
|
// "jsonLogs": log as structured JSON objects
|
||||||
// "databaseURI": a uri like mongodb://localhost:27017/dbname to tell us
|
// "databaseURI": a uri like mongodb://localhost:27017/dbname to tell us
|
||||||
@@ -186,7 +186,7 @@ class ParseServer {
|
|||||||
});
|
});
|
||||||
// Pass the push options too as it works with the default
|
// Pass the push options too as it works with the default
|
||||||
const pushControllerAdapter = loadAdapter(push && push.adapter, ParsePushAdapter, push || {});
|
const pushControllerAdapter = loadAdapter(push && push.adapter, ParsePushAdapter, push || {});
|
||||||
const loggerControllerAdapter = loadAdapter(loggerAdapter, FileLoggerAdapter);
|
const loggerControllerAdapter = loadAdapter(loggerAdapter, WinstonLoggerAdapter);
|
||||||
const emailControllerAdapter = loadAdapter(emailAdapter);
|
const emailControllerAdapter = loadAdapter(emailAdapter);
|
||||||
const cacheControllerAdapter = loadAdapter(cacheAdapter, InMemoryCacheAdapter, {appId: appId});
|
const cacheControllerAdapter = loadAdapter(cacheAdapter, InMemoryCacheAdapter, {appId: appId});
|
||||||
const analyticsControllerAdapter = loadAdapter(analyticsAdapter, AnalyticsAdapter);
|
const analyticsControllerAdapter = loadAdapter(analyticsAdapter, AnalyticsAdapter);
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ export default {
|
|||||||
},
|
},
|
||||||
"customPages": {
|
"customPages": {
|
||||||
env: "PARSE_SERVER_CUSTOM_PAGES",
|
env: "PARSE_SERVER_CUSTOM_PAGES",
|
||||||
help: "custom pages for pasword validation and reset",
|
help: "custom pages for password validation and reset",
|
||||||
action: objectParser
|
action: objectParser
|
||||||
},
|
},
|
||||||
"maxUploadSize": {
|
"maxUploadSize": {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ LOGS_FOLDER = process.env.PARSE_SERVER_LOGS_FOLDER || LOGS_FOLDER;
|
|||||||
const JSON_LOGS = process.env.JSON_LOGS || false;
|
const JSON_LOGS = process.env.JSON_LOGS || false;
|
||||||
|
|
||||||
let currentLogsFolder = LOGS_FOLDER;
|
let currentLogsFolder = LOGS_FOLDER;
|
||||||
|
const additionalTransports = [];
|
||||||
|
|
||||||
function generateTransports(level, options = {}) {
|
function generateTransports(level, options = {}) {
|
||||||
let transports = [
|
let transports = [
|
||||||
@@ -32,7 +33,7 @@ function generateTransports(level, options = {}) {
|
|||||||
level: 'error'
|
level: 'error'
|
||||||
}
|
}
|
||||||
), options)
|
), options)
|
||||||
];
|
].concat(additionalTransports);
|
||||||
if (!process.env.TESTING || process.env.VERBOSE) {
|
if (!process.env.TESTING || process.env.VERBOSE) {
|
||||||
transports = [
|
transports = [
|
||||||
new (winston.transports.Console)(
|
new (winston.transports.Console)(
|
||||||
@@ -90,5 +91,14 @@ export function addGroup(groupName) {
|
|||||||
return winston.loggers.get(groupName);
|
return winston.loggers.get(groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { logger };
|
export function addTransport(transport) {
|
||||||
|
const level = winston.level;
|
||||||
|
additionalTransports.push(transport);
|
||||||
|
const transports = generateTransports(level);
|
||||||
|
logger.configure({
|
||||||
|
transports: transports
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { logger, addTransport };
|
||||||
export default logger;
|
export default logger;
|
||||||
|
|||||||
Reference in New Issue
Block a user