avatar
@bangbang93

nestjs provider TRANSIENT作用域下获取注入目标

5/13/2021, 12:41:39 PM

最近在写nestjs-bunyan的时候,想要实现decorator自动创建childLogger,记录当前class的功能,最初的实现也很简单粗暴,在decorator上记录当前类名,然后给每个类名创建一个Provider。

但是这样做缺点也很明显,在应用启动后,没法创建新的日志模块,也不能手动添加日志模块。正好最近公司基建在做日志改造,就决定优化一下这个逻辑。

经过一阵深思,觉得nestjs的TRANSIENT作用域比较符合我的要求,相当于每次请求日志都需要给我一个新的对象,但是文档并没有提到如何在provider的构造方法里获知是哪个类需要被注入。

在尝试了一阵this和无脑Google后,并没有找到什么有效的文章,于是决定研究一下源码。

经过一阵阅读和搜索,我找到了https://github.com/nestjs/nest/blob/99ee3fd99341bcddfa408d1604050a9571b19bc9/packages/core/injector/inquirer/inquirer-providers.ts INQUIRER这个Provider,看名字似乎有点符合我的需求,于是顺着这个provider找到了https://github.com/nestjs/nest/issues/3819这个issue,确认了这确实是我要的东西,只是还没有在文档中体现,那剩下的就简单多了,把logger 的provider修改为

    {
      provide: BunyanLogger,
      scope: Scope.TRANSIENT,
      inject: [Logger, INQUIRER],
      useFactory(logger: Logger, a: Constructor) {
        return logger.child({components: a?.constructor.name})
      },
    }, {
      provide: BunyanRequestLogger,
      scope: Scope.REQUEST,
      inject: [Logger, INQUIRER, REQUEST, 'Options'],
      useFactory(logger: Logger, a: Constructor, req: Request, options: IOptions) {
        logger = logger.child({components: a?.constructor.name, reqId: req?.headers[options.reqIdHeader]})
        if (options.customRequestLogger) {
          logger = options.customRequestLogger(logger, req)
        }
        return logger
      },
    }