如何在NestJS中优雅地记录Request对象?
解决NestJS Logger打印Request对象显示
[object Object]的问题 问题原因
NestJS的@nestjs/common/Logger默认会将传入的消息转为字符串(调用对象的toString()方法),而JavaScript中普通对象的toString()返回值就是[object Object]。相比之下,console.log会自动序列化对象并处理循环引用,因此能正常展示对象详情。
解决方案
1. 手动提取Request关键属性序列化
直接打印整个Request对象会触发循环引用问题(比如req.res指向回req),建议只提取调试所需的核心字段再转为JSON字符串:
控制器修改示例:
@Get() findAll(@Req() request: Request): string { const reqDebugInfo = { method: request.method, url: request.url, query: request.query, body: request.body, clientIp: request.ip, userAgent: request.get('User-Agent') }; this.logger.log(JSON.stringify(reqDebugInfo, null, 2)); return this.messagesService.findAll(); }
服务修改示例:
findAll(): string { const reqDebugInfo = { method: this.request.method, url: this.request.url, query: this.request.query }; this.logger.log(JSON.stringify(reqDebugInfo, null, 2)); return "all messages"; }
2. 使用Node.js内置util.inspect处理循环引用
Node.js的util.inspect工具可以安全序列化带循环引用的对象,且支持自定义输出格式:
先导入util模块:
import * as util from 'util';
然后在日志中使用:
this.logger.log(util.inspect(request, { depth: null, // 展开所有层级的属性 colors: false, // 禁用ANSI颜色,避免Logger输出乱码 compact: false // 格式化换行输出 }));
3. 扩展NestJS Logger实现自动对象序列化
创建自定义Logger类,重写日志方法以自动处理对象类型的消息:
import { Logger } from '@nestjs/common'; import * as util from 'util'; export class ObjectFriendlyLogger extends Logger { log(message: any, context?: string) { this.processMessage(message, context, 'log'); } error(message: any, trace?: string, context?: string) { this.processMessage(message, context, 'error', trace); } warn(message: any, context?: string) { this.processMessage(message, context, 'warn'); } debug(message: any, context?: string) { this.processMessage(message, context, 'debug'); } verbose(message: any, context?: string) { this.processMessage(message, context, 'verbose'); } private processMessage(message: any, context: string | undefined, level: string, trace?: string) { const formattedMsg = typeof message === 'object' ? util.inspect(message, { depth: null, colors: false, compact: false }) : message; switch(level) { case 'log': super.log(formattedMsg, context); break; case 'error': super.error(formattedMsg, trace, context); break; case 'warn': super.warn(formattedMsg, context); break; case 'debug': super.debug(formattedMsg, context); break; case 'verbose': super.verbose(formattedMsg, context); break; } } }
之后在控制器和服务中使用自定义Logger:
private readonly logger = new ObjectFriendlyLogger(MessagesController.name);
内容的提问来源于stack exchange,提问作者Marcus Junius Brutus
相关产品推荐
相关产品推荐

