V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NorthA
V2EX  ›  Node.js

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

  •  
  •   NorthA · 272 天前 · 1448 次点击
    这是一个创建于 272 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问一下各位大佬 我如果想以以下的方式去使用 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)
    	}
    }
    
    20 条回复    2023-08-10 00:40:22 +08:00
    NorthA
        1
    NorthA  
    OP
       272 天前
    总感觉要是写一个模块,就得 provide 一次,那 100 个 service 就得导入 100 次,这种比较重复性的工作感觉没必要
    不传参,暴露一个方法去动态设置也行,不过我就是想知道 nestjs 有没有什么特性能解决这个问题,毕竟初学想了解一下😊
    RomeoHong
        2
    RomeoHong  
       272 天前
    也可以在 LoggerModule 上 providers 多个 LoggerService ,如:AppLoggerService, OtherLoggerService..., 这样可以不用使用 useValue 吧
    ilaipi
        3
    ilaipi  
       272 天前


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

    @Injectable()
    export class XService implements OnModuleInit {

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

    ```
    NorthA
        11
    NorthA  
    OP
       272 天前
    @April5 想着使用一下 nestjs 的特性来完成这个事情,在类里面 new 一下这个就没用上 nestjs 的特性了
    April5
        12
    April5  
       272 天前   ❤️ 1
    @NorthA #11 不是,在 app.useLogger 注入你的自定义 logger 不就可以了?
    Shamiko
        13
    Shamiko  
       272 天前   ❤️ 1
    app.useLogger(app.get(XXLogger))
    或者 Logger.overrideLogger(moduleRef.get(XXLogger))
    然后直接 new Logger(XXService.name)
    NorthA
        14
    NorthA  
    OP
       272 天前
    @April5 @Shamiko 谢谢了,我知道怎么弄了
    lee88688
        15
    lee88688  
       271 天前 via Android
    感觉楼主更想要一个工厂函数,根据不同的参数创建,或者根据当前的 module 的情况创建。
    NorthA
        16
    NorthA  
    OP
       271 天前
    @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
        18
    kobememory  
       264 天前   ❤️ 1
    kobememory
        19
    kobememory  
       264 天前
    https://imgur.com/a/fntkmtP
    图片发不出来??
    NorthA
        20
    NorthA  
    OP
       261 天前
    @kobememory 没错没错,就是这种差不多
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2978 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:16 · PVG 22:16 · LAX 07:16 · JFK 10:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.