Code coverage report for core/src/apm/timed.ts

Statements: 91.11% (41 / 45)      Branches: 77.78% (14 / 18)      Functions: 100% (14 / 14)      Lines: 90.24% (37 / 41)      Ignored: none     

All files » core/src/apm/ » timed.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 1181 1 1 1 1     1         1                                   1 3 3 3     3 3   6   3 8   8       6     6     6 6                   5                   1 2 2 2     2 2   3 2 3   3       3     3     3 3                   3                
import {acceptFilter, Filter} from '../decorators';
import {Lookup} from '../decorators/lookup';
import {logger, MSG_FMT} from '../internal/log';
import {Providers} from '../providers';
import {joinFqn, Tags} from '../util';
 
 
export abstract class TimerWrapper<T> {
  abstract wrap(func: (...args: unknown[]) => T): (...args: unknown[]) => T;
}
 
 
export abstract class TimerWrapperFactory {
  abstract timer<T>(name: string, tags?: Tags): TimerWrapper<T>;
 
 
  abstract asyncTimer<T>(name: string, tags?: Tags): TimerWrapper<Promise<T>>;
}
 
 
export type TimedOptions = {
  name?: string;
  timerWrapper?: TimerWrapperFactory;
  tags?: Tags;
  filter?: Filter;
}
 
type NotPromise<T> = Exclude<T, Promise<T>>;
 
 
export function Timed<T, P extends NotPromise<T>>(options: TimedOptions = {}): MethodDecorator {
  return function timedMethod(target: Record<string, any>, prop: PropertyKey, desc: PropertyDescriptor): void {
    const original = desc.value;
    const fqn = options.name || joinFqn(prop, target.constructor.name);
 
 
    const log = logger('@Timed');
    log.debug(MSG_FMT.annotatingMethod, target.constructor.name, prop, 'Timed', options);
 
    const lookup = new Lookup<TimerWrapperFactory, TimerWrapper<any>>(() => Providers.provide(TimerWrapperFactory));
 
    desc.value = function timed(...args: unknown[]): T {
      const apply = (): T => original.apply(this, ...args);
 
      return acceptFilter({
        filter: options,
        yes: () => {
          let _result: T;
          const wrapper = lookup.getInstance(
            this,
            fqn,
            () => lookup.getFactory(this, fqn, options.timerWrapper)?.asyncTimer(fqn, options.tags),
          );
 
          Eif (wrapper) {
            _result = wrapper.wrap(apply)();
          }
          else {
            _result = apply();
            log.warn(
              'Unable to decorate %s.%s with @TimedAsync() no TimerWrapperFactory provider to wrap call!',
              target.constructor.name,
              prop,
            );
          }
          return _result;
        }
        ,
        no: apply,
      });
    };
  }
}
 
 
export function TimedAsync<T, P extends Promise<T>>(options: TimedOptions = {}): MethodDecorator {
  return function timedMethod(target: Record<string, any>, prop: PropertyKey, desc: PropertyDescriptor): void {
    const original = desc.value;
    const fqn = options.name || joinFqn(prop, target.constructor.name);
 
 
    const log = logger('@TimedAsync');
    log.debug(MSG_FMT.annotatingMethod, target.constructor.name, prop, 'Timed', options);
 
    const lookup = new Lookup<TimerWrapperFactory, TimerWrapper<any>>(() => Providers.provide(TimerWrapperFactory));
    desc.value = function timed(...args: unknown[]): Promise<T> {
      const apply = (): Promise<T> => original.apply(this, ...args);
 
      return acceptFilter({
        filter: options,
        yes: () => {
          let _result: Promise<T>;
          const wrapper = lookup.getInstance(
            this,
            fqn,
            () => lookup.getFactory(this, fqn, options.timerWrapper)?.asyncTimer(fqn, options.tags),
          );
 
          Eif (wrapper) {
            _result = wrapper.wrap(apply)();
          }
          else {
            _result = apply();
            log.warn(
              'Unable to decorate %s.%s with @TimedAsync() no TimerWrapperFactory provider to wrap call!',
              target.constructor.name,
              prop,
            );
          }
          return _result;
        }
        ,
        no: apply,
      });
    };
  }
}