По итогу заработало так. Metadata - обёртка над Reflect.
export function LoggerInit(options: ILoggerClass = defaultClassLoggerOptions): ClassDecorator {
options = Object.assign({}, defaultClassLoggerOptions, options);
return function (target) {
target.prototype.logger = log;
options.name = options.name || target.name;
Metadata.set("__loggerOptions", options, target);
}
}
export function debug(options: ILoggerMethod = defaultMethodLoggerOptions): MethodDecorator {
options = Object.assign({}, defaultMethodLoggerOptions, options);
return function (target: Object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<any>) {
return {
value: function (...args) {
return descriptorWrapper.call(this, "debug", descriptor.value, options, propertyKey, args);
}
}
}
}
async function descriptorWrapper(logMethod,
originValue,
options,
propertyKey,
args) {
let res;
let isPromise: boolean;
try {
res = await originValue.apply(this, args);
isPromise = true;
}
catch (e) {
res = originValue.apply(this, args);
isPromise = false;
}
const classOptions = Metadata.get("__loggerOptions", this);
if (classOptions && classOptions.enabled && options.enabled) {
const data = [`[${classOptions.name}].${options.name || propertyKey}`];
if (options.withParams && !!args && !!args.length) {
data.push(`params: ${args.map(
a => JSON.stringify(a))
.join()}`);
}
if (options.withResult) {
data.push(`result ${JSON.stringify(res)}`);
}
log[logMethod](data.join(" | "));
}
return (isPromise) ? Promise.resolve(res) : res;
}