在装饰器中使用全局嵌套模块 [英] Use global nest module in decorator

查看:128
本文介绍了在装饰器中使用全局嵌套模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在嵌套中有一个全局记录器模块,该模块记录到云记录服务.我试图创建一个添加日志记录功能的类方法装饰器.但是我正在努力如何在装饰器中注入全局嵌套模块的服务,因为我在文档中发现的所有依赖项注入机制都依赖于基于类或类属性的注入.

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 how to inject the service of a global nest module inside a decorator, since all dependency injection mechanisms I found in the docs depend are class or class property based injection.

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

更新:按要求提供一个简单示例 基本示例是使用我的自定义记录器(在我的情况下,它记录到云服务)记录对服务方法的调用:

UPDATE: Per reqest a simple example Basic example would be to log calls to a service method using my custom logger (which in my case logs to a cloud service):

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

另一个扩展用例是捕获一些错误,然后将其记录下来.我有很多这种逻辑可以在我所有的服务中重复使用.

Another extended use case would be to catch some errors, then log them. I have a lot of this kind of logic that get reused across all my services.

推荐答案

好的,找到了解决方案.万一其他人偶然发现了这个.首先,请记住装饰器的工作原理-它们是基于类构造函数的,而不是基于实例的.

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.

就我而言,我想将记录器服务注入类实例中.因此,解决方案是告诉装饰器中的Nest将LoggerService注入到包含装饰方法的类的实例中.

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

这篇关于在装饰器中使用全局嵌套模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆