Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
fileignoreconfig:
- filename: pnpm-lock.yaml
checksum: a4f592e8bcc46e37d9b118deb6ac0c9a452c3392092cf716b16bae6fb037102d
- filename: packages/contentstack-utilities/src/logger/logger.ts
checksum: ddde5120404e55a0bc7b56223009ea2111d392e387037f6471c5e7b6388ae38b
version: '1.0'
29 changes: 26 additions & 3 deletions packages/contentstack-utilities/src/logger/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class Logger {
winston.format.printf((info) => {
// Apply minimal redaction for files (debugging info preserved)
const redactedInfo = this.redact(info, false);
return JSON.stringify(redactedInfo);
return this.safeStringify(redactedInfo);
}),
),
}),
Expand Down Expand Up @@ -117,6 +117,26 @@ export default class Logger {
}
}

/**
* Stringifies a log entry without throwing on circular references.
* `redact()` can fall back to the original (still-circular) object when
* cloning fails, so this must never assume the input is cycle-free.
*/
private safeStringify(value: any): string {
const seen = new WeakSet();
try {
return JSON.stringify(value, (_key, val) => {
if (typeof val === 'object' && val !== null) {
if (seen.has(val)) return '[Circular]';
seen.add(val);
}
return val;
});
} catch {
return JSON.stringify({ level: value?.level, message: value?.message ?? '[Unserializable log entry]' });
}
}

private shouldLog(level: LogType, target: 'console' | 'file'): boolean {
// If console logging is disabled, don't log to console
if (target === 'console' && this.config.consoleLoggingEnabled === false) {
Expand Down Expand Up @@ -186,9 +206,12 @@ export default class Logger {
this.loggers.error.error(logPayload);
}

// For console, use debug level if hidden, otherwise error level
// For console, use debug level if hidden, otherwise error level. Each level's
// winston logger instance bundles both the file and console transports, so only
// write again here when the target differs from the one already written above —
// otherwise this would duplicate both the console line and the file entry.
const consoleLevel: LogType = params.hidden ? 'debug' : 'error';
if (this.shouldLog(consoleLevel, 'console')) {
if (consoleLevel !== 'error' && this.shouldLog(consoleLevel, 'console')) {
this.loggers[consoleLevel].error(logPayload);
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@contentstack/cli-audit": "~1.19.5",
"@contentstack/cli-cm-export": "~1.25.3",
"@contentstack/cli-cm-import": "~1.33.5",
"@contentstack/cli-auth": "~1.8.4",
"@contentstack/cli-auth": "~1.8.5",
"@contentstack/cli-cm-bootstrap": "~1.19.7",
"@contentstack/cli-cm-branches": "~1.8.3",
"@contentstack/cli-cm-bulk-publish": "~1.12.1",
Expand Down