@dvsa/appdev-api-common
Version:
Utils library for common API functionality
87 lines (86 loc) • 3.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimedWithAccessor = TimedWithAccessor;
exports.Timed = Timed;
const node_perf_hooks_1 = require("node:perf_hooks");
/**
* Decorator to log the duration of a method execution by passing in an accessor function to retrieve the logger.
* @param getLogger - A function that takes the class instance and returns the logger instance.
* @param {string} label - Optional label for the log message.
*
* Note: If you are already using a logger as a class property, you can use the `Timed` decorator instead.
*
* @constructor
*
* Example usage:
* class MyClass {
* @TimedWithAccessor(() => Container.get(LOGGER))
* async findAll() {} // The log name here will be [findAll]
* }
*/
function TimedWithAccessor(getLogger, label) {
return (_target, propertyKey, descriptor) => {
const originalMethod = descriptor.value;
// biome-ignore lint/suspicious/noExplicitAny: "any" is correct for this context
descriptor.value = function (...args) {
const logger = getLogger(this);
const labelToUse = label || propertyKey;
const start = node_perf_hooks_1.performance.now();
try {
const result = originalMethod.apply(this, args);
// async route, if it's a Promise.
if (result instanceof Promise) {
return result
.then((res) => {
const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
logger.debug(`[${labelToUse}] took ${duration}ms`);
return res;
})
.catch((err) => {
const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
logger.debug(`[${labelToUse}] failed after ${duration}ms`);
throw err;
});
}
// Otherwise, sync method: log and return
const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
logger.debug(`[${labelToUse}] took ${duration}ms`);
return result;
}
catch (err) {
const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
logger.debug(`[${labelToUse}] failed after ${duration}ms`);
throw err;
}
};
return descriptor;
};
}
/**
* Decorator to log the duration of a method execution.
* @param {string} label - Optional label for the log message.
*
* Note: This decorator can be used on any class method that has a `logger` property.
* This method will throw an error if the `logger` property is not found on the class instance.
* If you are not using logger as a class property, you can use `LogDurationWithAccessor` instead.
* @constructor
*
* Example usage:
* class MyClass {
* private readonly logger = Container.get(Logger);
*
* @Timed()
* myMethod() {} // The log name here will be [myMethod]
*
* @Timed('MyClass.myMethod')
* myMethodWithOptName() {} // The log name here will be [MyClass.myMethod]
* }
*/
function Timed(label) {
return TimedWithAccessor((cls) => {
if (!cls.logger) {
throw new Error(`[${label}] Logger not found on decorated class.`);
}
return cls.logger;
}, label);
}