在winston.format.combine中使用ecsFormat与自定义格式提供者遇JSON循环结构错误求解决
解决Winston组合ecsFormat与自定义格式时的循环引用JSON错误
错误原因
TypeError: Converting circular structure to JSON 是因为日志对象中存在循环引用(比如对象A引用对象B,B又反向引用A),当ecsFormat或自定义格式尝试将该对象序列化为JSON时触发异常。
可行解决方案
1. 定位循环引用来源
- 单独测试格式组件:先分别只启用ecsFormat或自定义格式,确认是哪部分引入了循环结构。比如:
// 测试ecsFormat单独使用 this.logger = winston.createLogger({ level: this.level, format: ecsFormat(), transports: [new Console()], }); - 打印调试日志:在自定义格式中用Node.js内置的
util.inspect查看完整日志对象,定位循环引用的属性:const util = require('util'); // 在自定义格式生成函数中添加 const createFormat = (category) => { return winston.format((info) => { // 打印完整对象,depth: null显示所有层级 console.log(util.inspect(info, { depth: null })); info.category = category; return info; })(); };
2. 清理日志对象中的循环引用
实现一个工具函数,递归移除或标记循环引用的属性,再传入格式处理:
function cleanCircularReferences(obj, seen = new WeakSet()) { if (typeof obj !== 'object' || obj === null) return obj; if (seen.has(obj)) return '[Circular Reference]'; seen.add(obj); const cleaned = Array.isArray(obj) ? [] : {}; for (const key in obj) { cleaned[key] = cleanCircularReferences(obj[key], seen); } seen.delete(obj); return cleaned; } // 在格式组合中优先处理循环引用 this.logger = winston.createLogger({ level: this.level, format: winston.format.combine( winston.format(info => cleanCircularReferences(info))(), ecsFormat(), this.formatProvider.createFormat(this.category) ), transports: [new Console()], });
3. 配置ecsFormat排除/处理循环字段
ecsFormat默认可能捕获HTTP请求/响应这类自带循环引用的对象,可通过配置过滤:
- 排除指定字段:
ecsFormat({ exclude: ['req', 'res'] // 移除可能带循环的请求/响应对象 }) - 自定义字段转换:只保留需要的属性,避免序列化整个对象:
ecsFormat({ transform: (info) => { if (info.req) { // 仅保留请求的关键属性 info.req = { method: info.req.method, url: info.req.url, remoteAddress: info.req.connection.remoteAddress }; } return info; } })
4. 调整自定义格式逻辑
如果是自定义格式生成的字段导致循环,直接修改逻辑:
- 避免将完整的复杂对象(如req、res、数据库连接实例)加入日志,只提取需要的属性值。
- 检查自定义格式中是否有相互引用的字段,比如
info.parent = info这类错误赋值。
内容的提问来源于stack exchange,提问作者Krish909
相关产品推荐
相关产品推荐

