@imqueue/core
Version:
Simple JSON-based messaging queue for inter service communication
224 lines • 7.27 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.IMQ_LOG_TIME_FORMAT = exports.IMQ_LOG_ARGS = exports.IMQ_LOG_TIME = exports.IMQ_LOG_LEVEL = exports.LogLevel = void 0;
exports.verifyLogLevel = verifyLogLevel;
exports.logDebugInfo = logDebugInfo;
exports.profile = profile;
/*!
* Decorator: @profile
*
* I'm Queue Software Project
* Copyright (C) 2025 imqueue.com <support@imqueue.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* If you want to use this code in a closed source (commercial) project, you can
* purchase a proprietary commercial license. Please contact us at
* <support@imqueue.com> to get commercial licensing options.
*/
require("reflect-metadata");
var LogLevel;
(function (LogLevel) {
// noinspection JSUnusedGlobalSymbols
LogLevel["LOG"] = "log";
LogLevel["INFO"] = "info";
LogLevel["WARN"] = "warn";
LogLevel["ERROR"] = "error";
})(LogLevel || (exports.LogLevel = LogLevel = {}));
/**
* Checks if log level is set to proper value or returns default one
*
* @param {*} level
* @return {LogLevel}
*/
function verifyLogLevel(level) {
switch (level) {
case LogLevel.LOG:
case LogLevel.INFO:
case LogLevel.WARN:
case LogLevel.ERROR:
return level;
default:
return LogLevel.INFO;
}
}
exports.IMQ_LOG_LEVEL = verifyLogLevel(process.env.IMQ_LOG_LEVEL);
const DEFAULT_OPTIONS = {
logLevel: exports.IMQ_LOG_LEVEL,
};
/**
* Environment variable IMQ_LOG_TIME=[1, 0] - enables/disables profiled
* timings logging
*
* @type {boolean}
*/
exports.IMQ_LOG_TIME = !!+(process.env.IMQ_LOG_TIME || 0);
/**
* Environment variable IMQ_LOG_ARGS=[1, 0] - enables/disables profiled
* call arguments to be logged
*
* @type {boolean}
*/
exports.IMQ_LOG_ARGS = !!+(process.env.IMQ_LOG_ARGS || 0);
/**
* Environment variable IMQ_LOG_TIME_FORMAT=[
* 'microseconds',
* 'milliseconds',
* 'seconds'
* ]. Specifies profiled time logging format, by default is 'microseconds'
*
* @type {AllowedTimeFormat | string}
*/
exports.IMQ_LOG_TIME_FORMAT = process.env.IMQ_LOG_TIME_FORMAT || 'microseconds';
/**
* Prints debug information
*
* @param {boolean} debugTime
* @param {boolean} debugArgs
* @param {string} className
* @param {any[]} args
* @param {string} methodName
* @param {number} start
* @param {ILogger} logger
* @param {LogLevel} logLevel
*/
function logDebugInfo({ debugTime, debugArgs, className, args, methodName, start, logger, logLevel, }) {
const log = logger && typeof logger[logLevel] === 'function'
? logger[logLevel].bind(logger) : undefined;
if (debugTime) {
// noinspection TypeScriptUnresolvedFunction
const time = parseInt((process.hrtime.bigint() - BigInt(start)), 10) / 1000;
let timeStr;
// istanbul ignore next
switch (exports.IMQ_LOG_TIME_FORMAT) {
case 'milliseconds':
timeStr = (time / 1000).toFixed(3) + ' ms';
break;
case 'seconds':
timeStr = (time / 1000000).toFixed(3) + ' sec';
break;
default:
timeStr = time + ' μs';
break;
}
if (log) {
log(`${className}.${methodName}() executed in ${timeStr}`);
}
}
if (debugArgs) {
let argStr = '';
const cache = [];
try {
argStr = JSON.stringify(args, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (~cache.indexOf(value)) {
try {
return JSON.parse(JSON.stringify(value));
}
catch (error) {
return;
}
}
cache.push(value);
}
return value;
}, 2);
}
catch (err) {
logger.error(err);
}
if (log) {
log(`${className}.${methodName}() called with args: ${argStr}`);
}
}
}
/**
* Implements '@profile' decorator.
*
* @example
* ~~~typescript
* import { profile } from '@imqueue/core';
*
* class MyClass {
*
* @profile(true) // forced profiling
* public myMethod() {
* // ...
* }
*
* @profile() // profiling happened only depending on env DEBUG flag
* private innerMethod() {
* // ...
* }
* }
* ~~~
*
* @return {(
* target: any,
* methodName: (string),
* descriptor: TypedPropertyDescriptor<(...args: any[]) => any>
* ) => void}
*/
function profile(options) {
options = Object.assign({}, DEFAULT_OPTIONS, options);
const { enableDebugTime, enableDebugArgs, logLevel } = options;
let debugTime = exports.IMQ_LOG_TIME;
let debugArgs = exports.IMQ_LOG_ARGS;
if (typeof enableDebugTime === 'boolean') {
debugTime = enableDebugTime;
}
if (typeof enableDebugArgs === 'boolean') {
debugArgs = enableDebugArgs;
}
return function wrapper(target, methodName, descriptor) {
/* istanbul ignore next */
const original = descriptor.value || target[methodName];
descriptor.value = function (...args) {
if (!(debugTime || debugArgs)) {
return original.apply(this || target, args);
}
/* istanbul ignore next */
const className = typeof target === 'function' && target.name
? target.name // static
: target.constructor.name; // dynamic
// noinspection TypeScriptUnresolvedFunction
const start = process.hrtime.bigint();
const result = original.apply(this || target, args);
const debugOptions = {
args,
className,
debugArgs,
debugTime,
logLevel: logLevel ? verifyLogLevel(logLevel) : exports.IMQ_LOG_LEVEL,
logger: (this || target).logger,
methodName,
start,
};
/* istanbul ignore next */
if (result && typeof result.then === 'function') {
// async call detected
result.then((res) => {
logDebugInfo(debugOptions);
return res;
}).catch(() => {
logDebugInfo(debugOptions);
});
return result;
}
logDebugInfo(debugOptions);
return result;
};
};
}
//# sourceMappingURL=profile.js.map
;