Use global nest module in decorator

后端 未结 1 1923
一整个雨季
一整个雨季 2021-01-21 15:17

I have a global logger module in nest, that logs to a cloud logging service. I am trying to create a class method decorator that adds logging functionality. But I am struggling

相关标签:
1条回答
  • 2021-01-21 16:05

    Okay, found a solution. In case anyone else stumbles upon this. First please keep in mind how decorators work – they are class constructor based, not instance based.

    In my case I wanted to have my logger service injected in the class instance. So the solution is to tell Nest in the decorator to inject the LoggerService into the instance of the class that contains the decorated method.

    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;
            }
          }
        };
      };
    }
    

    This gives the possibility to catch errors in a method, log them within the service context, and either re-throw them (so your controllers can handle user resp) or not. In my case I also had to implement some transaction-related logic here.

    export class FoobarService implements OnModuleInit {
      onModuleInit() {
        this.test();
      }
    
      @logErrorDecorator()
      test() {
        throw new Error('Oh my');
      }
    }
    
    0 讨论(0)
提交回复
热议问题