'use strict';
var f = require('util').format,
MongoError = require('../error').MongoError;
// Filters for classes
var classFilters = {};
var filteredClasses = {};
var level = null;
// Save the process id
var pid = process.pid;
// current logger
var currentLogger = null;
/**
* @callback Logger~loggerCallback
* @param {string} msg message being logged
* @param {object} state an object containing more metadata about the logging message
*/
/**
* Creates a new Logger instance
* @class
* @param {string} className The Class name associated with the logging instance
* @param {object} [options=null] Optional settings.
* @param {Logger~loggerCallback} [options.logger=null] Custom logger function;
* @param {string} [options.loggerLevel=error] Override default global log level.
*/
var Logger = function(className, options) {
if (!(this instanceof Logger)) return new Logger(className, options);
options = options || {};
// Current reference
this.className = className;
// Current logger
if (options.logger) {
currentLogger = options.logger;
} else if (currentLogger == null) {
// eslint-disable-next-line no-console
currentLogger = console.log;
}
// Set level of logging, default is error
if (options.loggerLevel) {
level = options.loggerLevel || 'error';
}
// Add all class names
if (filteredClasses[this.className] == null) classFilters[this.className] = true;
};
/**
* Log a message at the debug level
* @method
* @param {string} message The message to log
* @param {object} object additional meta data to log
* @return {null}
*/
Logger.prototype.debug = function(message, object) {
if (
this.isDebug() &&
((Object.keys(filteredClasses).length > 0 && filteredClasses[this.className]) ||
(Object.keys(filteredClasses).length === 0 && classFilters[this.className]))
) {
var dateTime = new Date().getTime();
var msg = f('[%s-%s:%s] %s %s', 'DEBUG', this.className, pid, dateTime, message);
var state = {
type: 'debug',
message: message,
className: this.className,
pid: pid,
date: dateTime
};
if (object) state.meta = object;
currentLogger(msg, state);
}
};
/**
* Log a message at the warn level
* @method
* @param {string} message The message to log
* @param {object} object additional meta data to log
* @return {null}
*/
(Logger.prototype.warn = function(message, object) {
if (
this.isWarn() &&
((Object.keys(filteredClasses).length > 0 && filteredClasses[this.className]) ||
(Object.keys(filteredClasses).length === 0 && classFilters[this.className]))
) {
var dateTime = new Date().getTime();
var msg = f('[%s-%s:%s] %s %s', 'WARN', this.className, pid, dateTime, message);
var state = {
type: 'warn',
message: message,
className: this.className,
pid: pid,
date: dateTime
};
if (object) state.meta = object;
currentLogger(msg, state);
}
}),
/**
* Log a message at the info level
* @method
* @param {string} message The message to log
* @param {object} object additional meta data to log
* @return {null}
*/
(Logger.prototype.info = function(message, object) {
if (
this.isInfo() &&
((Object.keys(filteredClasses).length > 0 && filteredClasses[this.className]) ||
(Object.keys(filteredClasses).length === 0 && classFilters[this.className]))
) {
var dateTime = new Date().getTime();
var msg = f('[%s-%s:%s] %s %s', 'INFO', this.className, pid, dateTime, message);
var state = {
type: 'info',
message: message,
className: this.className,
pid: pid,
date: dateTime
};
if (object) state.meta = object;
currentLogger(msg, state);
}
}),
/**
* Log a message at the error level
* @method
* @param {string} message The message to log
* @param {object} object additional meta data to log
* @return {null}
*/
(Logger.prototype.error = function(message, object) {
if (
this.isError() &&
((Object.keys(filteredClasses).length > 0 && filteredClasses[this.className]) ||
(Object.keys(filteredClasses).length === 0 && classFilters[this.className]))
) {
var dateTime = new Date().getTime();
var msg = f('[%s-%s:%s] %s %s', 'ERROR', this.className, pid, dateTime, message);
var state = {
type: 'error',
message: message,
className: this.className,
pid: pid,
date: dateTime
};
if (object) state.meta = object;
currentLogger(msg, state);
}
}),
/**
* Is the logger set at info level
* @method
* @return {boolean}
*/
(Logger.prototype.isInfo = function() {
return level === 'info' || level === 'debug';
}),
/**
* Is the logger set at error level
* @method
* @return {boolean}
*/
(Logger.prototype.isError = function() {
return level === 'error' || level === 'info' || level === 'debug';
}),
/**
* Is the logger set at error level
* @method
* @return {boolean}
*/
(Logger.prototype.isWarn = function() {
return level === 'error' || level === 'warn' || level === 'info' || level === 'debug';
}),
/**
* Is the logger set at debug level
* @method
* @return {boolean}
*/
(Logger.prototype.isDebug = function() {
return level === 'debug';
});
/**
* Resets the logger to default settings, error and no filtered classes
* @method
* @return {null}
*/
Logger.reset = function() {
level = 'error';
filteredClasses = {};
};
/**
* Get the current logger function
* @method
* @return {Logger~loggerCallback}
*/
Logger.currentLogger = function() {
return currentLogger;
};
/**
* Set the current logger function
* @method
* @param {Logger~loggerCallback} logger Logger function.
* @return {null}
*/
Logger.setCurrentLogger = function(logger) {
if (typeof logger !== 'function') throw new MongoError('current logger must be a function');
currentLogger = logger;
};
/**
* Set what classes to log.
* @method
* @param {string} type The type of filter (currently only class)
* @param {string[]} values The filters to apply
* @return {null}
*/
Logger.filter = function(type, values) {
if (type === 'class' && Array.isArray(values)) {
filteredClasses = {};
values.forEach(function(x) {
filteredClasses[x] = true;
});
}
};
/**
* Set the current log level
* @method
* @param {string} level Set current log level (debug, info, error)
* @return {null}
*/
Logger.setLevel = function(_level) {
if (_level !== 'info' && _level !== 'error' && _level !== 'debug' && _level !== 'warn') {
throw new Error(f('%s is an illegal logging level', _level));
}
level = _level;
};
module.exports = Logger;