diff --git a/packages/contentstack-utilities/src/logger/logger.ts b/packages/contentstack-utilities/src/logger/logger.ts index 6c5575b0d0..02d14640c7 100644 --- a/packages/contentstack-utilities/src/logger/logger.ts +++ b/packages/contentstack-utilities/src/logger/logger.ts @@ -85,7 +85,12 @@ export default class Logger { } } - if (showConsoleLogs) { + // Errors and warnings must always reach the console, even when progress bars + // suppress info/success/debug output — otherwise failures (e.g. an invalid + // stack API key or a taxonomy error) are silently swallowed in progress mode. + const isErrorOrWarn = level === 'error' || level === 'warn'; + + if (showConsoleLogs || isErrorOrWarn) { transports.push( new winston.transports.Console({ format: winston.format.combine( diff --git a/packages/contentstack-utilities/test/unit/logger.test.ts b/packages/contentstack-utilities/test/unit/logger.test.ts index a840e46a3e..0bd8f3992b 100644 --- a/packages/contentstack-utilities/test/unit/logger.test.ts +++ b/packages/contentstack-utilities/test/unit/logger.test.ts @@ -233,6 +233,70 @@ describe('Logger', () => { }); }); +describe('Console output in progress-manager mode', () => { + const tempDir = path.join(os.tmpdir(), `csdx-progress-log-${Date.now()}`); + + function hasConsoleTransport(winLogger: any): boolean { + return winLogger.transports.some((t: any) => t.constructor && t.constructor.name === 'Console'); + } + + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log') return { progressSupportedModule: 'bulk-operations', showConsoleLogs: false }; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'bulk-operations'; + if (key === 'sessionId') return 'test-session'; + return undefined; + }) + .it('keeps console output for errors when progress bars suppress info logs', () => { + const progressLogger = new Logger({ basePath: tempDir, consoleLogLevel: 'info', logLevel: 'info' }); + expect(hasConsoleTransport(progressLogger['loggers'].error)).to.equal(true); + }); + + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log') return { progressSupportedModule: 'bulk-operations', showConsoleLogs: false }; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'bulk-operations'; + if (key === 'sessionId') return 'test-session'; + return undefined; + }) + .it('keeps console output for warnings when progress bars suppress info logs', () => { + const progressLogger = new Logger({ basePath: tempDir, consoleLogLevel: 'info', logLevel: 'info' }); + expect(hasConsoleTransport(progressLogger['loggers'].warn)).to.equal(true); + }); + + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log') return { progressSupportedModule: 'bulk-operations', showConsoleLogs: false }; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'bulk-operations'; + if (key === 'sessionId') return 'test-session'; + return undefined; + }) + .it('suppresses console output for info logs so progress bars stay clean', () => { + const progressLogger = new Logger({ basePath: tempDir, consoleLogLevel: 'info', logLevel: 'info' }); + expect(hasConsoleTransport(progressLogger['loggers'].info)).to.equal(false); + }); + + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log') return { progressSupportedModule: 'bulk-operations', showConsoleLogs: true }; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'bulk-operations'; + if (key === 'sessionId') return 'test-session'; + return undefined; + }) + .it('shows console output for info logs when console logging is enabled', () => { + const progressLogger = new Logger({ basePath: tempDir, consoleLogLevel: 'info', logLevel: 'info' }); + expect(hasConsoleTransport(progressLogger['loggers'].info)).to.equal(true); + }); +}); + describe('Session Log Path', () => { let sandbox: sinon.SinonSandbox; let tempDir: string;