Использовать модуль глобального гнезда в декораторе - PullRequest
0 голосов
/ 07 марта 2020

У меня есть модуль глобального логгера в гнезде, который входит в сервис облачного логинга. Я пытаюсь создать декоратор метода класса, который добавляет функциональность регистрации. Но я изо всех сил пытаюсь внедрить службу глобального модуля nest внутри декоратора, так как все механизмы внедрения зависимостей, которые я нашел в документации, зависят от класса или внедрения на основе свойств класса.

export function logDecorator() {

  // I would like to inject a LoggerService that is a provider of a global logger module
  let logger = ???

  return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
    //get original method
    const originalMethod = propertyDescriptor.value;

    //redefine descriptor value within own function block
    propertyDescriptor.value = function(...args: any[]) {
      logger.log(`${propertyKey} method called with args.`);

      //attach original method implementation
      const result = originalMethod.apply(this, args);

      //log result of method
      logger.log(`${propertyKey} method return value`);
    };
  };
}

ОБНОВЛЕНИЕ: По запросу простой пример Basi c пример будет регистрировать вызовы к методу сервиса, используя мой собственный регистратор (который в моем случае регистрирует в облачной службе ):

class MyService {
    @logDecorator()
    someMethod(name: string) {
        // calls to this method as well as method return values would be logged to CloudWatch
        return `Hello ${name}`
    }
}

Другим расширенным вариантом использования будет перехват некоторых ошибок, а затем их регистрация. У меня есть много подобных логи c, которые используются во всех моих службах.

1 Ответ

1 голос
/ 10 марта 2020

Хорошо, нашел решение. На случай, если кто-то еще наткнется на это. Прежде всего, имейте в виду, как работают декораторы - они основаны на конструкторах классов, а не на экземплярах.

В моем случае я хотел, чтобы моя служба логгера была внедрена в экземпляр класса. Таким образом, решение состоит в том, чтобы сказать Nest в декораторе, чтобы он вставлял LoggerService в экземпляр класса, который содержит декорированный метод.

import { Inject } from '@nestjs/common';
import { LoggerService } from '../../logger/logger.service';

export function logErrorDecorator(bubble = true) {
  const injectLogger = Inject(LoggerService);

  return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
    injectLogger(target, 'logger'); // this is the same as using constructor(private readonly logger: LoggerService) in a class

    //get original method
    const originalMethod = propertyDescriptor.value;

    //redefine descriptor value within own function block
    propertyDescriptor.value = async function(...args: any[]) {
      try {
        return await originalMethod.apply(this, args);
      } catch (error) {
        const logger: LoggerService = this.logger;

        logger.setContext(target.constructor.name);
        logger.error(error.message, error.stack);

        // rethrow error, so it can bubble up
        if (bubble) {
          throw error;
        }
      }
    };
  };
}

Это дает возможность отлавливать ошибки в методе, регистрировать их в контекст службы, и либо перебрасывать их (чтобы ваши контроллеры могли обрабатывать пользователей соответственно), либо нет. В моем случае мне также пришлось реализовать некоторые логики транзакций c здесь.

export class FoobarService implements OnModuleInit {
  onModuleInit() {
    this.test();
  }

  @logErrorDecorator()
  test() {
    throw new Error('Oh my');
  }
}
...