Skip to content

Commit a3230d9

Browse files
authored
Merge pull request #2675 from contentstack/fix/logger-circular-object-parsing
fixed circular object parsing bug
2 parents 147ef23 + 96e3d19 commit a3230d9

3 files changed

Lines changed: 28 additions & 5 deletions

File tree

‎.talismanrc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
fileignoreconfig:
22
- filename: pnpm-lock.yaml
3-
checksum: 763c12b0555cbd63ca4015664e08de315f0e675125a34de2d9c8d1a73a3723e8
3+
checksum: 3894686f64c8bf322cb7917c79193268344c68037ef1a41808f1509fc227087d
44
version: '1.0'

‎packages/contentstack-utilities/src/logger/logger.ts‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export default class Logger {
6565
winston.format.printf((info) => {
6666
// Apply minimal redaction for files (debugging info preserved)
6767
const redactedInfo = this.redact(info, false);
68-
return JSON.stringify(redactedInfo);
68+
return this.safeStringify(redactedInfo);
6969
}),
7070
),
7171
}),
@@ -117,6 +117,26 @@ export default class Logger {
117117
}
118118
}
119119

120+
/**
121+
* Stringifies a log entry without throwing on circular references.
122+
* `redact()` can fall back to the original (still-circular) object when
123+
* cloning fails, so this must never assume the input is cycle-free.
124+
*/
125+
private safeStringify(value: any): string {
126+
const seen = new WeakSet();
127+
try {
128+
return JSON.stringify(value, (_key, val) => {
129+
if (typeof val === 'object' && val !== null) {
130+
if (seen.has(val)) return '[Circular]';
131+
seen.add(val);
132+
}
133+
return val;
134+
});
135+
} catch {
136+
return JSON.stringify({ level: value?.level, message: value?.message ?? '[Unserializable log entry]' });
137+
}
138+
}
139+
120140
private shouldLog(level: LogType, target: 'console' | 'file'): boolean {
121141
// If console logging is disabled, don't log to console
122142
if (target === 'console' && this.config.consoleLoggingEnabled === false) {
@@ -186,9 +206,12 @@ export default class Logger {
186206
this.loggers.error.error(logPayload);
187207
}
188208

189-
// For console, use debug level if hidden, otherwise error level
209+
// For console, use debug level if hidden, otherwise error level. Each level's
210+
// winston logger instance bundles both the file and console transports, so only
211+
// write again here when the target differs from the one already written above —
212+
// otherwise this would duplicate both the console line and the file entry.
190213
const consoleLevel: LogType = params.hidden ? 'debug' : 'error';
191-
if (this.shouldLog(consoleLevel, 'console')) {
214+
if (consoleLevel !== 'error' && this.shouldLog(consoleLevel, 'console')) {
192215
this.loggers[consoleLevel].error(logPayload);
193216
}
194217
}

‎packages/contentstack/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,4 @@
162162
}
163163
},
164164
"repository": "https://github.com/contentstack/cli"
165-
}
165+
}

0 commit comments

Comments
 (0)