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

2023-07-30 01:06:16 +08:00
 NorthA

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

// user.service.ts
@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/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({
	imports: [UserModule, LoggerModule],
	controllers: [AppController],
	providers: [AppService],
})
export class AppModule {}

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

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

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

@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)
	}
}
1724 次点击
所在节点    Node.js
20 条回复
NorthA
2023-07-30 01:26:35 +08:00
总感觉要是写一个模块,就得 provide 一次,那 100 个 service 就得导入 100 次,这种比较重复性的工作感觉没必要
不传参,暴露一个方法去动态设置也行,不过我就是想知道 nestjs 有没有什么特性能解决这个问题,毕竟初学想了解一下😊
RomeoHong
2023-07-30 01:59:25 +08:00
也可以在 LoggerModule 上 providers 多个 LoggerService ,如:AppLoggerService, OtherLoggerService..., 这样可以不用使用 useValue 吧
ilaipi
2023-07-30 07:19:59 +08:00


使用 `DynamicModule` 试试? 在 AppModule 里注册全局的,在任意 module 就都能用了
lee88688
2023-07-30 07:30:55 +08:00
#3 楼的方法应该可以的,全局注册的 module 起导出的 service 在任何地方都可以使用,可以看看 nest 自带的一些模块例如 config ,注册方式可以全局也可以局部。
NorthA
2023-07-30 09:35:04 +08:00
@ilaipi 我目前是直接用了 @Global ,然后在 app.module 中全局注册了,看着大佬你这个写法,我的疑惑点还是有的,就是我的 logger 构造器里面有个参数,这个参数怎么传
NorthA
2023-07-30 09:39:24 +08:00
@lee88688 可能大佬没回复到我想要的点上,举个简单的例子,我有 a ,b ,c ,d 四个模块,logger 已经全局注册了,就是想 a,b,c,d 在使用 logger 的时候给构造器传递一个参数,我目前只知道在 provides 里面去引入 logger 然后使用 useValue 传参
NorthA
2023-07-30 09:49:36 +08:00
@RomeoHong 😂这个感觉就是把 provides 的地方换了一个
ilaipi
2023-07-30 10:26:21 +08:00
@NorthA #5 在 forRootAsync 这个方法调用的时候,需要传一个 factory 的方法,这个方法里你就可以传参数了。变化形式有很多,得自己思考思考
NorthA
2023-07-30 10:37:07 +08:00
@ilaipi #8 ok ,谢谢大佬
April5
2023-07-30 12:53:26 +08:00
没太理解你的意思,不过看你需求,直接在类里面 new 一个 Logger 就好了好像。
```
import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class XService implements OnModuleInit {

private readonly logger = new Logger(XService.name);

```
NorthA
2023-07-30 13:36:41 +08:00
@April5 想着使用一下 nestjs 的特性来完成这个事情,在类里面 new 一下这个就没用上 nestjs 的特性了
April5
2023-07-30 15:51:20 +08:00
@NorthA #11 不是,在 app.useLogger 注入你的自定义 logger 不就可以了?
Shamiko
2023-07-30 18:32:26 +08:00
app.useLogger(app.get(XXLogger))
或者 Logger.overrideLogger(moduleRef.get(XXLogger))
然后直接 new Logger(XXService.name)
NorthA
2023-07-30 20:38:33 +08:00
@April5 @Shamiko 谢谢了,我知道怎么弄了
lee88688
2023-07-30 22:43:53 +08:00
感觉楼主更想要一个工厂函数,根据不同的参数创建,或者根据当前的 module 的情况创建。
NorthA
2023-07-30 23:00:49 +08:00
@lee88688 #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 了传参也是可行
kobememory
2023-08-07 15:43:37 +08:00
kobememory
2023-08-07 15:51:18 +08:00
kobememory
2023-08-07 15:53:05 +08:00
https://imgur.com/a/fntkmtP
图片发不出来??
NorthA
2023-08-10 00:40:22 +08:00
@kobememory 没错没错,就是这种差不多

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/960887

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX