173 lines
4.7 KiB
JavaScript
173 lines
4.7 KiB
JavaScript
/**
|
|
* @fileOverview Utilities to simplify logging for the rest of the code.
|
|
*/
|
|
const winston = require('winston');
|
|
const _ = require('lodash');
|
|
const debug = require('debug')('logging:compliance');
|
|
|
|
/**
|
|
* Requiring `winston-mongodb` will expose
|
|
* `winston.transports.MongoDB`
|
|
*/
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
require('winston-mongodb');
|
|
|
|
module.exports = logging;
|
|
|
|
const MONGO_LOG_COLLECTION = 'ComplianceLog';
|
|
|
|
/**
|
|
* Initialise log transports
|
|
*/
|
|
const transports = [
|
|
new winston.transports.Console({
|
|
'name': 'console.info',
|
|
'format': winston.format.combine(
|
|
winston.format.timestamp(),
|
|
winston.format.simple()
|
|
),
|
|
'colorize': true,
|
|
'silent': false
|
|
})
|
|
];
|
|
let mongoTransport;
|
|
|
|
/**
|
|
* Create a very basic logger
|
|
*/
|
|
const logger = winston.createLogger({
|
|
'level': 'info',
|
|
transports
|
|
});
|
|
|
|
/**
|
|
* Trivially handle the 'error' event to prevent unhandled exception errors.
|
|
*/
|
|
logger.on('error', (error) => {
|
|
debug('Logger error:', error);
|
|
});
|
|
|
|
/**
|
|
* Initialisation functions
|
|
*/
|
|
module.exports.init = {
|
|
initMongoTransport
|
|
};
|
|
|
|
/**
|
|
* For test, also export a way to control the logger
|
|
*/
|
|
module.exports._test = {
|
|
'getLogger': () => logger,
|
|
'getTransports': () => transports
|
|
};
|
|
|
|
/**
|
|
* @typedef {function} BridgeLogFunction
|
|
* @param {Object} req - Express request object (to access IP, request ID, etc.)
|
|
* @param {string} [req.ip] - The IP address of the caller
|
|
* @param {string} [req.bridgeUniqueId] - The unique id of this request
|
|
* @param {string} [req.sessionData.User] - UserID for the user the request is for
|
|
* @param {string} msg - The basic message to log
|
|
* @param {Object} [opt] - Optional object containing additional values to log. These will be
|
|
* automatically prefixed with '_' and added to the logged object.
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} BridgeLog
|
|
* @property {BridgeLogFunction} info - log at info level
|
|
* @property {BridgeLogFunction} error - log at error level
|
|
*/
|
|
|
|
/**
|
|
* Factory function for initialising logging for the specified calling file.
|
|
*
|
|
* It returns an object containing log functions such as `log.info()`, `log.error()`.
|
|
* The format of this functions is defined as @see BridgeLogFunction.
|
|
*
|
|
* @example
|
|
* const log = require('<path>/utils/logging.js')(__filename, 'utils:text:example');
|
|
* log.info(req, 'Some info text I want to log');
|
|
* log.error(req, 'Some error text I want to log', {customValue: 'Some custom value for this log'});
|
|
*
|
|
* @param {string} file - The filename. Usually just __filename
|
|
* @param {string} logID - A colon seperated id for this log group (e.g as used by debug())
|
|
* @returns {BridgeLog} - The logging object
|
|
*/
|
|
function logging(file, logID) {
|
|
return {
|
|
'info': doLog.bind(undefined, file, logID, 'info'),
|
|
'error': doLog.bind(undefined, file, logID, 'error')
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Function to actually do the logging for any of the specific functions specified above.
|
|
*
|
|
* @param {string} file - the full filepath of the file that initialised this logger
|
|
* @param {string} logId - id of the log group
|
|
* @param {string} level - log level
|
|
* @param {Object} req - Express request object (to access IP, requestID etc.)
|
|
* @param {string} msg - The simple string to log
|
|
* @param {Object} opt - Additional options to log
|
|
*/
|
|
function doLog(file, logId, level, req, msg, opt) {
|
|
const toLog = {
|
|
level,
|
|
'message': msg,
|
|
'meta': {
|
|
logId,
|
|
'ip': req.ip,
|
|
'reqId': req.bridgeUniqueId,
|
|
'userId': _.get(req, 'session.data.user'),
|
|
file
|
|
}
|
|
};
|
|
const loggableOpt = _.mapKeys(opt, (value, key) => `_${ key}`);
|
|
|
|
//
|
|
// Update the base object with the loggable options (prefix with _ per GELF);
|
|
//
|
|
_.assign(toLog.meta, loggableOpt);
|
|
|
|
//
|
|
// Call the real logger and return the result
|
|
//
|
|
return logger.log(toLog);
|
|
}
|
|
|
|
/**
|
|
* The MongoDB `Db` class from the NodeJS driver
|
|
* @typedef {Object} Db
|
|
*/
|
|
|
|
/**
|
|
* Updates the logger to include a MongoDB transport that talks to the provided
|
|
* `db` instance.
|
|
* This also removes any prior MongoDB transport.
|
|
*
|
|
* @param {Db} db - the MongoDB `Db` instance to use for calling the DB.
|
|
*/
|
|
function initMongoTransport(db) {
|
|
// Remove any existing mongodb transport
|
|
if (mongoTransport)
|
|
logger.remove(mongoTransport);
|
|
|
|
//
|
|
// Create a new mongodb transport and register it with the logger
|
|
//
|
|
mongoTransport = new winston.transports.MongoDB({
|
|
'name': 'mongotransport',
|
|
'decolorize': true,
|
|
'storeHost': true,
|
|
db,
|
|
'collection': MONGO_LOG_COLLECTION,
|
|
'format': winston.format.combine(
|
|
winston.format.timestamp(),
|
|
winston.format.printf((info) => info.message)
|
|
)
|
|
});
|
|
|
|
logger.add(mongoTransport);
|
|
}
|