All files / src/utils patchLogger.ts

87.23% Statements 41/47
66.67% Branches 20/30
100% Functions 10/10
87.23% Lines 41/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152        5x 5x 5x 5x   5x       5x   5x 5x 5x   5x       5x   5x 25x   1x   1x       1x               5x   5x   13x 13x     13x         13x 2x       11x                                 11x   11x 10x                     1x                                     5x 35x 35x   41x 41x       41x 33x 33x             33x   33x   33x       8x           46x                  
/**
 * Provide function to patch Winston logger
 * to add dynamic props for each logs
 */
const { LEVEL, SPLAT } = require("triple-beam");
const path = require("path"),
	callerId = require("caller-id"),
	readPkgUp = require("read-pkg-up");
 
export function patchLogger(
	loggy,
	{ patchConSole = false }: { patchConSole?: boolean } = {}
) {
	_patchMainLog(loggy);
 
	_patchShortcut(loggy);
	Eif (patchConSole) {
		_patchConsole(loggy);
	}
	return loggy;
}
//overriding dirty console methods
function _patchConsole(loggy) {
	let levels = ["log", "error", "warn", "info", "debug"];
 
	levels.forEach(level => {
		console[level] = function __patchConsole(...args) {
			//getting the caller
			let caller = callerId.getData(__patchConsole); //expensive to generate call stack..
 
			Iif (Object.keys(loggy.levels).includes(level)) {
				return loggy.log.call({ caller }, level, ...args);
			}
 
			return loggy.log.call({ caller }, "info", ...args);
		};
	});
}
 
//monkey patching the main log function
//https://github.com/winstonjs/winston/blob/master/lib/winston/logger.js#L149
function _patchMainLog(loggy) {
	let _log = loggy.log; //ref 2 the original func
 
	loggy.log = function __log(level, msg, ...splat) {
		//getting dynamic data
		let caller = this.caller || callerId.getData(__log); //expensive to generate call stack..
		let PKG = readPkgUp.sync({ cwd: path.dirname(caller.filePath) })
			.package;
 
		let props = {
			label: PKG.name,
			caller: getRelativePathOfCaller(caller)
		};
 
		if (arguments.length === 1) {
			return _log.call(loggy, Object.assign({}, props, level));
		}
 
		// Slightly less hotpath, but worth optimizing for.
		Iif (arguments.length === 2) {
			if (msg && typeof msg === "object" && !(msg instanceof Error)) {
				msg[LEVEL] = msg.level = level;
 
				return _log.call(loggy, Object.assign({}, props, msg));
			}
 
			return _log.call(
				loggy,
				Object.assign({}, props, {
					[LEVEL]: level,
					level,
					message: msg
				})
			);
		}
 
		const meta = splat[splat.length - 1]; //metadata always at end!!
 
		if (typeof meta === "object" && meta !== null) {
			return _log.call(
				loggy,
				Object.assign({}, props, meta, {
					meta, //to always have meta prop
					[LEVEL]: level,
					[SPLAT]: splat, //.slice(0, -1),
					level,
					message: msg
				})
			);
		} else {
			return _log.call(
				loggy,
				Object.assign({}, props, {
					[LEVEL]: level,
					[SPLAT]: splat,
					level,
					message: msg
				})
			);
		}
 
		return new Error(
			"Fatal, this should never reached!! https://github.com/winstonjs/winston/blob/master/lib/winston/logger.js#L149"
		);
	};
}
//https://github.com/winstonjs/winston/blob/master/lib/winston/create-logger.js
//gotta patch each "levels" (info, debug, blablabla) since theres a hotpath branch for function call with 1 arg
function _patchShortcut(loggy) {
	Object.keys(loggy.levels).map(function(level) {
		let originFunc = loggy[level];
		loggy[level] = function __shortCut(...args) {
			//getting dynamic data
			let caller = callerId.getData(__shortCut); //expensive to generate call stack..
			let PKG = readPkgUp.sync({ cwd: path.dirname(caller.filePath) })
				.package;
 
			//hotpath
			if (args.length === 1) {
				const [msg] = args;
				const info = (msg &&
					/**https://github.com/winstonjs/winston/issues/1338?_pjax=%23js-repo-pjax-container#issuecomment-436915825*/
					!(msg instanceof Error) &&
					msg.message &&
					msg) || { message: msg };
 
				//Decorate extra stuff here
				info.label = info.label || PKG.name;
 
				info.caller = getRelativePathOfCaller(caller);
				//Done
				return originFunc.call(loggy, info);
			}
 
			//otherwise propagating caller context
			return loggy.log.call({ caller }, level, ...args);
		};
	});
}
 
function getRelativePathOfCaller(caller) {
	return path
		.normalize(
			`${path.relative(process.cwd(), caller.filePath)}:${
				caller.lineNumber
			}`
		)
		.split(/[\\\/]/g)
		.join(path.posix.sep);
}