我和我的团队沉迷了几天,以找出在开发期间编写调试级别日志的正确位置。
我们正在使用winston
和winston-daily-rotate-file
来解耦日志记录过程的一部分,并使用nest-winston
(用于Winston logger的嵌套模块包装器)来分离。
我们决定通过扩展内置的Logger类来创建灵活的自定义记录器,作为服务。
@Injectable()
export class LoggerService extends Logger {
constructor(
@Inject('winston')
private readonly logger: winston.Logger,
) { super(); }
info(message: string, context?: string): void {
this.logger.info(message, { context });
super.log(message, context);
}
debug(message: string, context?: string): void {
// To delegate the call to the parent class, no winston used.
super.debug(message, context);
}
error(message: string, trace: string, context?: string): void {
this.logger.error(message, { context });
super.error(message, trace, context);
}
}
您可能已经从方法debug()
中注意到,存储设备(Transports)尚未故意在调试级别进行配置。我们希望仅在开发中通过控制台将它们打印出来。
现在,我们可以在相同上下文中的任何地方使用LoggerService。例如,
@Controller('users')
export class UsersController {
constructor(private readonly logger: LoggerService) {}
}
@Injectable()
export class UsersService {
constructor(private readonly logger: LoggerService) {}
// Inside a method, debug some logic.
this.logger.debug(message, UsersService.name);
}
这种方法一目了然,但是当代码被其他地方过度使用时,可能会变得非常混乱。
基于这个原因,我们认为应该在一个共享的位置上处理调试过程,并提出了一个让拦截器处理工作的想法。
import { LoggerService } from '../../logger/logger.service';
@Injectable()
export class DebuggingInterceptor implements NestInterceptor {
constructor(private readonly logger: LoggerService) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const ctx = `${context.getClass().name} ➜ ${context.getHandler().name}()`;
return next
.handle()
.pipe(
tap((response) => {
if (process.env.NODE_ENV === 'development') {
this.logger.debug(response, ctx);
}
}),
);
}
}
在打印调试日志之前,检查环境是否在开发中对我来说有点难看。
如果上面使用拦截器的方法可能完全错误,我会担心吗?
如何更好地解决此问题?
答案 0 :(得分:0)
我认为使用拦截器的方法很好。如果您不喜欢在拦截器中检查环境的想法,则可以随时在LoggerService
类中检查环境,以决定是否调用super.debug()
方法,那样您就可以致电this.logger.debug(response, ctx)
。
作为旁注,我正在开发自己的版本的记录器,并尝试将类名注入记录器中,以便在记录器中设置上下文并从那里使用它,但这需要一些时间。只是对另一个想法的想法。