isatdatapro-microservices
Version:
A library for creating microservices to access Inmarsat's IsatData Pro satellite IoT system
152 lines (141 loc) • 3.78 kB
JavaScript
/**
* Custom Winston logger producing JSON format
* {UTC timestamp, level, message, <meta>}
*/
;
/**
* logging module
* @module logging
*/
require('dotenv').config();
const { createLogger, format, transports, config } = require('winston');
const { combine, timestamp, colorize, printf } = format;
const logfileLevel = process.env.LOGFILE_LEVEL || 'info';
const logfileLocation = process.env.LOGFILE_LOCATION || `./logs/info.log`;
/**
* Generates the custom JSON formatting
* @private
* @param {object} info Logger object parameters and metadata
* @returns {string} formatted log entry
*/
const customFormat = printf(info => {
const expectedTags = [
'timestamp',
'level',
'message',
];
let formatString = `` +
`"timestamp":"${info.timestamp}",` +
`"level":"${info.level}",` +
`"message":"${info.message}"`;
for (let k in info) {
if (info.hasOwnProperty(k) && !expectedTags.includes(k)) {
formatString += ',' + `"${k}":"${info[k]}"`;
}
}
return '{' + formatString + '}';
});
//: Logger configuration for different outputs
const options = {
file: {
level: logfileLevel,
filename: logfileLocation,
handleException: true,
humanReadableUnhandledException: true,
maxsize: 5242880,
maxFiles: 5,
format: combine(
timestamp(),
customFormat,
),
},
console: {
level: 'debug',
format: combine(
timestamp(),
colorize(),
customFormat,
),
},
};
/**
* Instantiates the logger object with default file output
* TODO: test exception handling cases
*/
const logger = createLogger({
defaultMeta: { component: 'idp-microservices' },
transports: [
new transports.File(options.file)
],
/* Log exceptions to file
exceptionHandlers: [
new transports.File(options.file)
]
//*/
});
//: Log to console when not in production
if (process.env.NODE_ENV !== 'production') {
logger.add(new transports.Console(options.console));
}
//: Stream output to the log file
logger.stream = {
write: function(message, encoding) {
logger.info(message);
},
};
/**
* Returns the short name of the module
* @param {string} filename The file/path name of the module
* @returns {string}
*/
const getModuleName = (caller) => {
const modulePathParts = caller.split('/');
const moduleName = modulePathParts[modulePathParts.length - 1];
return moduleName;
}
/**
* Registers a calling module name for the logger as metadata.
* @param {string} caller The module name invoking the log
* @param {string} [component] Optional component name
*/
const loggerProxy = (caller, component) => {
const callerMeta = { module: `${getModuleName(caller)}`};
if (component) { callerMeta.component = component }
const getMeta = (meta) => {
if (meta instanceof Object && meta !== null) {
return Object.assign(callerMeta, meta);
}
return callerMeta;
}
const proxy = {
error: (msg, meta) => {
logger.error(msg, getMeta(meta));
},
warn: (msg, meta) => {
logger.warn(msg, getMeta(meta));
},
info: (msg, meta) => {
logger.info(msg, getMeta(meta));
},
verbose: (msg, meta) => {
logger.verbose(msg, getMeta(meta));
},
debug: (msg, meta) => {
logger.debug(msg, getMeta(meta));
},
silly: (msg, meta) => {
logger.silly(msg, getMeta(meta));
},
getModuleName: (caller) => {
return getModuleName(caller);
}
};
return proxy;
}
module.exports = { logger, loggerProxy };
/* QUICK LOCAL TEST - COMMENT THIS LINE TO RUN
const testPathName = '/various/path/parts/myFuncName.js';
let l = loggerProxy(testPathName);
l.warn('test message', {testMeta: "myTestMeta"});
console.log('Module: ' + l.getModuleName(testPathName));
//*/