NestJS 中如何便捷的动态设置自定义日志函数的 作用域参数 Nodejs

发布于 1周前 作者 eggper 来自 nodejs/Nestjs

问一下各位大佬 我如果想以以下的方式去使用 LoggerService ,并且需要传递参数,是不是只能在 module 文件里面 provide 使用 useValue 。 因为我已经把 Logger 设置成了全局模块了,感觉要是继续在 provide 使用 useValue 就感觉没做全局一样,有没有其它方式能处理这个传参,比如使用个注解之类的,有没有比较好的方法? 我就暑假这两天看了一下 nestjs 的文档,想看看上面的问题能不能就使用 nest 的一些特性去解决,有大佬给个思路也行

// user.service.ts
[@Injectable](/user/Injectable)()
export class UserService {
	constructor(private readonly logger: LoggerService) {}
 }

// user.module.ts @Module({ controllers: [UserController], providers: [ UserService, { provide: LoggerService, useValue: new LoggerService(‘user’), }, ], }) export class UserModule {}

// src/app.module.ts
import { Module } from '[@nestjs](/user/nestjs)/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { UserModule } from './user/user.module'
import { LoggerModule } from './libs/logger/logger.module'

[@Module](/user/Module)({
	imports: [UserModule, LoggerModule],
	controllers: [AppController],
	providers: [AppService],
})
export class AppModule {}

// src/libs/logger/logger.module.ts
import { Global, Module } from '[@nestjs](/user/nestjs)/common'
import { LoggerService } from './logger.service'

[@Global](/user/Global)()
[@Module](/user/Module)({
	providers: [LoggerService],
	exports: [LoggerService],
})
export class LoggerModule {}

// src/libs/logger/logger.service.ts
import { ConsoleLogger, Injectable, Scope } from '[@nestjs](/user/nestjs)/common'
import { Signale } from 'signale'

[@Injectable](/user/Injectable)({ scope: Scope.TRANSIENT })
export class LoggerService extends ConsoleLogger {
	private readonly logger: Signale
	private readonly scope: string

	constructor(scope = 'app') {
		super()

		this.logger = new Signale({
			stream: process.stdout,
			disabled: false,
			interactive: false,
		})

		this.scope = scope
		this.logger.scope(this.scope)
		this.logger.config({
			displayTimestamp: true, // 以 HH:MM:SS 的格式显示当前本地时间。
			displayDate: true, // 以 YYYY-MM-DD 的格式显示当前本地日期。
			displayFilename: false, // 显示记录器消息来源的文件名。
		})
	}

	complete(message: string, ...args: any[]) {
		this.logger.complete(message, ...args)
	}
}

NestJS 中如何便捷的动态设置自定义日志函数的 作用域参数 Nodejs

21 回复

总感觉要是写一个模块,就得 provide 一次,那 100 个 service 就得导入 100 次,这种比较重复性的工作感觉没必要
不传参,暴露一个方法去动态设置也行,不过我就是想知道 nestjs 有没有什么特性能解决这个问题,毕竟初学想了解一下😊


也可以在 LoggerModule 上 providers 多个 LoggerService ,如:AppLoggerService, OtherLoggerService…, 这样可以不用使用 useValue 吧



使用 DynamicModule 试试? 在 AppModule 里注册全局的,在任意 module 就都能用了

#3 楼的方法应该可以的,全局注册的 module 起导出的 service 在任何地方都可以使用,可以看看 nest 自带的一些模块例如 config ,注册方式可以全局也可以局部。

我目前是直接用了 ,然后在 app.module 中全局注册了,看着大佬你这个写法,我的疑惑点还是有的,就是我的 logger 构造器里面有个参数,这个参数怎么传

可能大佬没回复到我想要的点上,举个简单的例子,我有 a ,b ,c ,d 四个模块,logger 已经全局注册了,就是想 a,b,c,d 在使用 logger 的时候给构造器传递一个参数,我目前只知道在 provides 里面去引入 logger 然后使用 useValue 传参

😂这个感觉就是把 provides 的地方换了一个

#5 在 forRootAsync 这个方法调用的时候,需要传一个 factory 的方法,这个方法里你就可以传参数了。变化形式有很多,得自己思考思考

#8 ok ,谢谢大佬

没太理解你的意思,不过看你需求,直接在类里面 new 一个 Logger 就好了好像。
<br>import { Injectable, Logger } from 'nestjs/common';<br><br>()<br>export class XService implements OnModuleInit {<br><br> private readonly logger = new Logger(<a target="_blank" href="http://XService.name" rel="nofollow noopener">XService.name</a>);<br><br>

想着使用一下 nestjs 的特性来完成这个事情,在类里面 new 一下这个就没用上 nestjs 的特性了

#11 不是,在 app.useLogger 注入你的自定义 logger 不就可以了?

app.useLogger(app.get(XXLogger))
或者 Logger.overrideLogger(moduleRef.get(XXLogger))
然后直接 new Logger(XXService.name)

谢谢了,我知道怎么弄了

感觉楼主更想要一个工厂函数,根据不同的参数创建,或者根据当前的 module 的情况创建。

#15 是这么个感觉了,就是 logger 已经是全局了,我只用在 service 模块的构造器中

constructor(private readonly logger: LoggerService)
主要就是那个 scope 的参数传递,想用 nestjs 的特性去实现一下,因为是初学 nest 想折腾一下
不折腾我完全可以暴露一个 setScope 方法来动态设置
比如 (目前我是这么做了)看到 ConsoleLogger 里面也是实现了一个 setContext
constructor(private readonly logger: LoggerService) {
this.logger.setScope(service.name)
}
这样

又或者是直接导入 new 了传参也是可行

没错没错,就是这种差不多

在 NestJS 中动态设置自定义日志函数的作用域参数,你可以利用 NestJS 内置的 Logger 服务,并结合依赖注入(DI)系统来实现。以下是一个示例,展示如何在 NestJS 中实现这一点:

首先,创建一个自定义的日志服务,继承自 NestJS 的 Logger 类:

import { Injectable, LoggerService } from '@nestjs/common';

@Injectable()
export class CustomLogger extends LoggerService {
  log(message: string, context?: string) {
    const scopedMessage = `[${context || 'DEFAULT_CONTEXT'}] ${message}`;
    console.log(scopedMessage);
  }

  // 实现其他日志方法...
  error(message: string, trace?: string, context?: string) {
    const scopedMessage = `[${context || 'DEFAULT_CONTEXT'}] ${message}`;
    console.error(scopedMessage, trace);
  }

  // 可以继续实现 warn, debug, verbose 等方法...
}

然后,在你的模块中提供这个自定义日志服务:

import { Module } from '@nestjs/common';
import { CustomLogger } from './custom-logger.service';

@Module({
  providers: [
    {
      provide: LoggerService,
      useClass: CustomLogger,
    },
  ],
})
export class AppModule {}

现在,在你的服务或控制器中注入 LoggerService,并动态设置上下文:

import { Injectable, Inject, LoggerService } from '@nestjs/common';

@Injectable()
export class SomeService {
  constructor(@Inject(LoggerService) private readonly logger: LoggerService) {}

  someMethod() {
    this.logger.log('This is a log message', 'SomeContext');
  }
}

这样,你就可以在 NestJS 中动态设置自定义日志函数的作用域参数了。

回到顶部