UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

88 lines (87 loc) 3.5 kB
import { _ms } from '../datetime/time.util.js'; import { _assert } from '../error/assert.js'; import { SimpleMovingAverage } from '../math/sma.js'; import { _stringify } from '../string/stringify.js'; import { _getArgsSignature, _getMethodSignature } from './decorator.util.js'; /** * Console-logs when method had started, when it finished, time taken and if error happened. * Supports both sync and async methods. * Awaits if method returns a Promise. * * @example output: * * >> syncMethodSuccess() * << syncMethodSuccess() took 124 ms * * >> asyncMethod() * << asyncMethodThrow() took 10 ms ERROR: MyError */ // eslint-disable-next-line @typescript-eslint/naming-convention export function _LogMethod(opt = {}) { return (_target, key, descriptor) => { _assert(typeof descriptor.value === 'function', '@_LogMethod can be applied only to methods'); const originalFn = descriptor.value; const keyStr = String(key); const { avg, logArgs = true, logStart, logResult, logResultLength = true, logger = console, } = opt; let { logResultFn } = opt; if (!logResultFn) { if (logResult) { logResultFn = r => ['result:', _stringify(r)]; } else if (logResultLength) { logResultFn = r => (Array.isArray(r) ? [`result: ${r.length} items`] : []); } } const sma = avg ? new SimpleMovingAverage(avg) : undefined; let count = 0; descriptor.value = function (...args) { const started = Date.now(); const ctx = this; // e.g `NameOfYourClass.methodName` // or `NameOfYourClass(instanceId).methodName` const methodSignature = _getMethodSignature(ctx, keyStr); const argsStr = _getArgsSignature(args, logArgs); const callSignature = `${methodSignature}(${argsStr}) #${++count}`; if (logStart) logger.log(`>> ${callSignature}`); try { const res = originalFn.apply(ctx, args); if (res && typeof res.then === 'function') { // Result is a Promise, will wait for resolution or rejection return res .then((r) => { logFinished(logger, callSignature, started, sma, logResultFn, r); return r; }) .catch((err) => { logFinished(logger, callSignature, started, sma, logResultFn, undefined, err); throw err; }); } // not a Promise logFinished(logger, callSignature, started, sma, logResultFn, res); return res; } catch (err) { logFinished(logger, callSignature, started, sma, logResultFn, undefined, err); throw err; // rethrow } }; return descriptor; }; } // eslint-disable-next-line max-params function logFinished(logger, callSignature, started, sma, logResultFn, res, err) { const millis = Date.now() - started; const t = ['<<', callSignature, 'took', _ms(millis)]; if (sma) { t.push(`(avg ${_ms(sma.pushGetAvg(millis))})`); } if (err !== undefined) { t.push('ERROR:', err); } else if (logResultFn) { t.push(...logResultFn(res)); } logger.log(...t.filter(Boolean)); }