@dyihoon90/glogging
Version:
HTTP request logging middleware & transaction function decorator for express, using winston
194 lines • 9.49 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoggedClass = LoggedClass;
exports.LoggedMethod = LoggedMethod;
exports.LoggedFunction = LoggedFunction;
var GLogger_auditLogger_1 = require("./GLogger.auditLogger");
var ObjUtils_1 = require("./utils/ObjUtils");
/**
* Default options for transaction logging
*/
var DEFAULT_TXN_LOGGING_OPTIONS = {
toLogResults: false,
toLogSuccessTxn: true
};
/**
* #### Class decorator function that adds logging to all class methods
* - All class methods _must_ take in an IExpressRequest object (extended from express.Request) as first parameter
* - Creates success audit log of level `info` on return
* - Creates fail audit log of level `warn` on error thrown
* - Modifies all class methods except the constructor method
* - Arrow functions are _not_ considered class methods
* @param logger a GLogger instance
* @param metadata metadata including transaction category, transaction module, & optional filename
* @param options Optional option parameter
* - toLogResult - whether to log the return value of the decorated function. Defaults to false.
* - redactedProperties(optional) - if `toLogResult` set to true, use this array for properties you don't want logged out.
* @example result = [{key1: 'a',key2: 'b'}, {key1: 'c',key2: 'd'}]; redactedProperties = ['key1', 0]; loggedResult = [{key2: 'd'}]
*/
function LoggedClass(logger, metadata, options) {
return function (target) {
for (var _i = 0, _a = Reflect.ownKeys(target.prototype); _i < _a.length; _i++) {
var propertyName = _a[_i];
var descriptor = Reflect.getOwnPropertyDescriptor(target.prototype, propertyName);
var isMethod = (descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) instanceof Function;
if (!isMethod || propertyName === 'constructor') {
continue;
}
if (typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) === 'function') {
Object.defineProperty(target.prototype, propertyName, LoggedMethod(logger, metadata, options)(target, propertyName, descriptor));
}
// Object.defineProperty(target.prototype, propertyName, descriptor);
}
};
}
/**
* #### Method decorator function that adds logging to method
* - Methods _must_ take in an IExpressRequest object (extended from express.Request) as first parameter
* - Creates success audit log of level `info` on return
* - Creates fail audit log of level `warn` on error thrown
* - Modifies all class methods except the constructor method
* - Arrow functions are _not_ considered class methods
* @param logger a GLogger instance
* @param metadata metadata including transaction category, transaction module, & optional filename
* @param options Optional option parameter
* - toLogResult - whether to log the return value of the decorated function. Defaults to false.
* - redactedProperties(optional) - if `toLogResult` set to true, use this array for properties you don't want logged out.
* @example result = [{key1: 'a',key2: 'b'}, {key1: 'c',key2: 'd'}]; redactedProperties = ['key1', 0]; loggedResult = [{key2: 'd'}]
*/
function LoggedMethod(logger, metadata, options) {
return function (target, key, descriptor) {
var originalMethod = descriptor.value;
if (typeof originalMethod !== 'function') {
throw new TypeError("@LoggedMethod decorator can only be applied to methods not: ".concat(typeof originalMethod));
}
return {
configurable: false,
get: function () {
var _this = this;
if (this === target.prototype) {
return originalMethod;
}
descriptor.value = function (req) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
return executeFunctionWithLogs.apply(void 0, __spreadArray([logger, metadata, originalMethod.bind(_this), key, req, options], args, false));
};
var boundFn = descriptor.value;
return boundFn;
},
set: function (value) {
descriptor.value = value;
}
};
};
}
/**
* #### decorator function that adds logging to a normal function / arrow function
* - Function must take in an IExpressRequest object (extended from express.Request) as first parameter
* - Creates success audit log of level `info` on return
* - Creates fail audit log of level `warn` on error thrown
* @param logger a GLogger instance
* @param metadata metadata including transaction category, transaction module, & optional filename
* @param options Optional option parameter
* - toLogResult - whether to log the return value of the decorated function. Defaults to false.
* - redactedProperties(optional) - if `toLogResult` set to true, use this array for properties you don't want logged out.
* @example result = [{key1: 'a',key2: 'b'}, {key1: 'c',key2: 'd'}]; redactedProperties = ['key1', 0]; loggedResult = [{key2: 'd'}]
*/
function LoggedFunction(logger, metadata, options) {
return function (decoratedFunc, req) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
return executeFunctionWithLogs.apply(void 0, __spreadArray([logger, metadata, decoratedFunc, decoratedFunc.name, req, options], args, false));
};
}
/**
* Executes a function and logs the result
* @param logger a GLogger instance
* @param metadata metadata including transaction category, transaction module, & optional filename
* @param decoratedFunc the function to execute
* @param decoratedFuncName the name of the decorated function
* @param req the request object
* @param options optional logging options
* @param args the arguments to pass to the decorated function
* @returns
*/
function executeFunctionWithLogs(logger, _a, decoratedFunc, decoratedFuncName, req, options) {
var _b;
var trxCategory = _a.trxCategory, trxModule = _a.trxModule, filename = _a.filename;
var args = [];
for (var _i = 6; _i < arguments.length; _i++) {
args[_i - 6] = arguments[_i];
}
var startTime = new Date().getTime();
var fnName = String(decoratedFuncName);
var auditLoggerInstance = new GLogger_auditLogger_1.GLoggerAuditLogger(logger);
var logFailure = auditLoggerInstance.logTransactionFailure.bind(auditLoggerInstance, { req: req }, { trxCategory: trxCategory, filename: filename, trxName: fnName, trxModule: trxModule }, startTime);
try {
var promiseOrValue = decoratedFunc.apply(void 0, __spreadArray([req], args, false));
var opt_1 = __assign(__assign({}, DEFAULT_TXN_LOGGING_OPTIONS), options);
var logSuccess_1 = auditLoggerInstance.logTransactionSuccess.bind(auditLoggerInstance, "Transaction: ".concat(fnName, " success"), { req: req }, { trxCategory: trxCategory, filename: filename, trxName: fnName, trxModule: trxModule }, startTime);
var redact_1 = ObjUtils_1.redactProperties.bind(null, (_b = opt_1.redactedProperties) !== null && _b !== void 0 ? _b : []);
// Scenario where decoratedFunc is asynchronous returning Promise
if (promiseOrValue instanceof Promise) {
return promiseOrValue
.then(function (result) {
if (opt_1.toLogSuccessTxn) {
if (opt_1.toLogResults) {
opt_1.redactedProperties && result ? logSuccess_1(redact_1(result)) : logSuccess_1(result);
}
else {
logSuccess_1();
}
}
return result;
})
.catch(function (e) {
logFailure(e);
throw e;
});
}
// Scenario where decoratedFunc is synchronous returning value
// Why separate? if we `await` sync decoratedFunc, return value gets casted into Promise, becoming async
if (opt_1.toLogSuccessTxn) {
if (opt_1.toLogResults) {
opt_1.redactedProperties && promiseOrValue
? logSuccess_1(redact_1(promiseOrValue))
: logSuccess_1(promiseOrValue);
}
else {
logSuccess_1();
}
}
return promiseOrValue;
}
catch (e) {
logFailure(e);
throw e;
}
}
//# sourceMappingURL=GLogger.decorator.js.map