Skip to content
Merged
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: 1 addition & 1 deletion packages/logger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@user-office-software/duo-logger",
"version": "2.3.0",
"version": "2.3.1",
"description": "Logger implementation",
"author": "SWAP",
"license": "ISC",
Expand Down
113 changes: 113 additions & 0 deletions packages/logger/src/loggers/implementation/ConsoleLogger.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import safeStringify from 'fast-safe-stringify';
import { ConsoleLogger } from './ConsoleLogger';
import { LEVEL } from '../../enum/Level';

describe('ConsoleLogger', () => {
let consoleSpy: jest.SpyInstance;

beforeEach(() => {
consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
});

afterEach(() => {
consoleSpy.mockRestore();
});

test('logs info message without color when colorize is false', () => {
const logger = new ConsoleLogger(); // default config, colorize false
const context = { key: 'TestValue' };
const message = 'Test info message';
logger.logInfo(message, context);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
expect(loggedMessage).toContain(message);
expect(loggedMessage).toContain(LEVEL.INFO);
expect(loggedMessage).toContain('TestValue');
});

test('logs warn message with color when colorize is true', () => {
const logger = new ConsoleLogger({ colorize: true });
const context = { key: 'TestValue' };
const message = 'Test warn message';
logger.logWarn(message, context);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
const expectedLevel = `\x1b[33m${LEVEL.WARN}\x1b[0m`; // yellow for WARN
expect(loggedMessage).toContain(expectedLevel);
expect(loggedMessage).toContain(message);
expect(loggedMessage).toContain('TestValue');
});

test('logs error message with color when colorize is true', () => {
const logger = new ConsoleLogger({ colorize: true });
const context = { key: 'TestValue' };
const message = 'Test error message';
logger.logError(message, context);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
const expectedLevel = `\x1b[31m${LEVEL.ERROR}\x1b[0m`; // red for ERROR
expect(loggedMessage).toContain(expectedLevel);
expect(loggedMessage).toContain(message);
expect(loggedMessage).toContain('TestValue');
});

test('logs debug message without color even when colorize is true', () => {
const logger = new ConsoleLogger({ colorize: true });
const context = { key: 'TestValue' };
const message = 'Test debug message';
logger.logDebug(message, context);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
// DEBUG messages are not colorized
expect(loggedMessage).toContain(LEVEL.DEBUG);
expect(loggedMessage).toContain(message);
expect(loggedMessage).toContain('TestValue');
});

test('logs exception details when an Error instance is passed', () => {
const logger = new ConsoleLogger({ colorize: false });
const error = new Error('Something went wrong');
const message = 'Exception occurred';
const context = { key: 'TestValue' };

logger.logException(message, error, context);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
expect(loggedMessage).toContain(message);
expect(loggedMessage).toContain(error.message);
expect(loggedMessage).toContain('stack');
// because the context is merged, safeStringify(context) should be present
expect(loggedMessage).toContain('TestValue');
});

test('logs exception when a non-Error value is passed', () => {
const logger = new ConsoleLogger({ colorize: false });
const notError = 'simple string exception';
const message = 'Exception occurred';
const context = { key: 'TestValue' };

logger.logException(message, notError, context);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
expect(loggedMessage).toContain(message);
expect(loggedMessage).toContain(notError);
expect(loggedMessage).toContain('TestValue');
});

test('logs exception correctly when exception is null', () => {
const logger = new ConsoleLogger({ colorize: false });
const message = 'Null exception test';

logger.logException(message, null);

expect(consoleSpy).toHaveBeenCalled();
const loggedMessage = consoleSpy.mock.calls[0][0];
expect(loggedMessage).toContain(message);
});
});
30 changes: 20 additions & 10 deletions packages/logger/src/loggers/implementation/ConsoleLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { LEVEL } from '../../enum/Level';
import { Logger } from '../Logger';

export class ConsoleLogger implements Logger {
private readonly colorize: boolean;

constructor(config: { colorize: boolean } = { colorize: false }) {
this.colorize = config.colorize;
}

logInfo(message: string, context: Record<string, unknown>) {
this.log(LEVEL.INFO, message, context);
}
Expand Down Expand Up @@ -47,23 +53,27 @@ export class ConsoleLogger implements Logger {
}

log(level: LEVEL, message: string, context: Record<string, unknown>) {
// Color definitions
const colorReset = '\x1b[0m';
const colorRed = '\x1b[31m';
const colorYellow = '\x1b[33m';
const colorBold = '\x1b[1m';

let formattedLevel: string = level;
switch (level) {
case LEVEL.INFO:
formattedLevel = `${colorBold}${level}${colorReset}`;
break;
case LEVEL.ERROR:
formattedLevel = `${colorRed}${level}${colorReset}`;
break;
case LEVEL.WARN:
formattedLevel = `${colorYellow}${level}${colorReset}`;
break;
if (this.colorize) {
switch (level) {
case LEVEL.INFO:
formattedLevel = `${colorBold}${level}${colorReset}`;
break;
case LEVEL.ERROR:
formattedLevel = `${colorRed}${level}${colorReset}`;
break;
case LEVEL.WARN:
formattedLevel = `${colorYellow}${level}${colorReset}`;
break;
}
}
// If not colorized, use plain level text

console.log(
`[${new Date().toISOString()}] ${formattedLevel} - ${message} \n ${safeStringify(
Expand Down