winston-sugar
Version:
Syntactical sugar on to of winston, configure winston will be easy using .json configuration file
154 lines (137 loc) • 6.16 kB
JavaScript
const winston = require('winston');
const fs = require('fs');
const path = require('path');
/*
*/
const _loggerName = Symbol();
const _environment = Symbol();
const _configFile = Symbol();
const _loadTransports = Symbol();
const _combineFormat = Symbol();
/**
* Class Winston Loader
*/
class WinstonLoader {
/**
* WinstonLoader constructor function
* @param name (optional) - The name of the winston logger, default is winston
*/
constructor(name) {
this[_environment] = (process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';
this[_loggerName] = (name) ? name : 'winston';
this[_configFile] = {};
}
/**
* Use this function if you need to load the .json configurations files without initiating the winston logger.
* This should be called only once time in the begging of your application.
* @param filename - The file name including path ex: ./config/winston.json - you can change the file name
*/
loadConfigFile(filename) {
try {
const load = JSON.parse(fs.readFileSync(filename, 'utf8'));
for (let key in load) this[_configFile][key] = load[key];
} catch (e) {
console.log(e);
throw new Error(`Invalid config path or Problem in reading config.json from file`);
}
}
/**
* Use this function if you need to load the .json configurations and initiate the winston logger.
* This should be called only once time in the begging of your application.
* @param filename - The file name including path ex: ./config/winston.json - you can change the file name
*/
config(filename) {
this.loadConfigFile(filename);
// Set the default configuration options
const options = {
level: this[_configFile].level || 'info',
silent: this[_configFile].silent || false,
exitOnError: this[_configFile].exitOnError || true,
transports: [],
};
// Check is format parameter is defined, then we need to combine it's formats
if (this[_configFile].format) this[_combineFormat](this[_configFile].format, options);
// Check is transports parameter is defined, then we need to load all transports
if (this[_configFile].transports && this[_configFile].transports.length >
0) this[_loadTransports](this[_configFile].transports, options);
// Load Colors
// noinspection JSCheckFunctionSignatures
if (this[_configFile].levels && this[_configFile].levels.colors) winston.addColors(this[_configFile].levels.colors);
// check custom levels
if (this[_configFile].levels && this[_configFile].levels.values) options.levels = this[_configFile].levels.values;
// Load winston options
winston.loggers.add(this[_loggerName], options);
}
[_loadTransports](transports, destination) {
if (!destination) return;
for (let transport of transports) {
// Check is format parameter is defined, then we need to combine it's formats
if (transport.options.format ||
transport.options.filters) this[_combineFormat](transport.options.format, transport.options, transport.options.filters);
// Check transport environment
// noinspection JSValidateTypes
if (transport.env.toLowerCase() === this[_environment].toLowerCase())
try {
// Create new transport
destination.transports.push(new winston.transports[transport.type](transport.options));
} catch (e) {
throw new Error(`Invalid winston.transports.${transport.type} options parameters`);
}
}
}
[_combineFormat](formats, destination, filters) {
if (!destination) return;
if (formats || filters) {
const formatsAndFilters = [];
// Check filters
if (filters && filters.length > 0) {
const conditions = filters.map((e) => ' info.level === "' + e + '" ').join('||');
const callbackStr = `((info, opts) => { return (${conditions}) ? info : false; })`;
// Create s custom format according to the filters, and adding it to be combined
const callback = eval(callbackStr);
try {
formatsAndFilters.push(winston.format(callback)());
} catch (e) {
throw new Error('Invalid level information');
}
}
// Check formats
if (formats && formats.length > 0) {
for (let format of formats) {
// Check if type equals printf in order to pass the predefined template function
if (format.type && format.type === 'printf') {
try {
// Map & update printf options with passing a template cb function from winston json configurations printf.templates
if (format.options.template) format.options = eval(this[_configFile].printf.templates[format.options.template]);
} catch (e) {
throw new Error('Invalid winston.format.printf(cb) - callback function string error');
}
}
try {
// Adding format to be combined
formatsAndFilters.push(winston.format[format.type](format.options));
} catch (e) {
throw new Error(`Invalid winston.format.${format.type}() function signature name or options parameters`);
}
}
}
// Combine all formats or add a single format
destination.format = (formatsAndFilters.length > 1) ? winston.format.combine(...formatsAndFilters) : formatsAndFilters[0];
}
}
/**
* This function return an instance of winston logger
* @param category (optional) - If you need to have child logger for a specific module.
* @returns {winston.Logger} - return winston logger instance
*/
getLogger(category) {
if (!winston.loggers.get(this[_loggerName]))
throw new Error(`winston.Logger is not configured, please call config function first`);
if (category) {
return winston.loggers.get(this[_loggerName]).child({'category': category});
} else {
return winston.loggers.get(this[_loggerName]);
}
}
}
module.exports = new WinstonLoader();