Skip to content

Commit

Permalink
Add tests and allow logging numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
ghengeveld committed Oct 22, 2024
1 parent 5501f85 commit 9bd481b
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 2 deletions.
153 changes: 153 additions & 0 deletions node-src/lib/log.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { afterEach, beforeEach, describe, expect, it, MockInstance, vi } from 'vitest';

import { createLogger } from './log';

let consoleError: MockInstance<typeof console.error>;
let consoleWarn: MockInstance<typeof console.warn>;
let consoleInfo: MockInstance<typeof console.info>;
let consoleDebug: MockInstance<typeof console.debug>;

beforeEach(() => {
consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);
consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
consoleInfo = vi.spyOn(console, 'info').mockImplementation(() => undefined);
consoleDebug = vi.spyOn(console, 'debug').mockImplementation(() => undefined);

vi.useFakeTimers();
vi.setSystemTime(new Date().setTime(0));
});

afterEach(() => {
delete process.env.DISABLE_LOGGING;
delete process.env.LOG_LEVEL;
delete process.env.LOG_PREFIX;

consoleError.mockReset();
consoleWarn.mockReset();
consoleInfo.mockReset();
consoleDebug.mockReset();

vi.useRealTimers();
});

const timestamp = expect.stringMatching(/\d\d:\d\d:\d\d.\d\d\d/);

describe('log prefix', () => {
it('should use the log prefix from environment variables', () => {
process.env.LOG_PREFIX = 'env-prefix';
const logger = createLogger({});
logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith('env-prefix', 'message');
});

it('should use the log prefix from flags', () => {
process.env.LOG_PREFIX = 'env-prefix';
const logger = createLogger({ logPrefix: 'flag-prefix' });
logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith('flag-prefix', 'message');
});

it('should prefer the log prefix from options', () => {
process.env.LOG_PREFIX = 'env-prefix';
const logger = createLogger({ logPrefix: 'flag-prefix' }, { logPrefix: 'option-prefix' });
logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith('option-prefix', 'message');
});

it('should use a timestamp as prefix by default', () => {
const logger = createLogger({});
logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith(timestamp, 'message');
});

it('should not use a prefix if set to an empty string', () => {
process.env.LOG_PREFIX = '';
const logger = createLogger({});
logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith('message');
});

it('should not use a prefix in interactive mode', () => {
process.env.LOG_PREFIX = 'env-prefix';
const logger = createLogger({ interactive: true, logPrefix: 'flag-prefix' });
logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith('message');
});
});

describe('log levels', () => {
it('should ignore debug messages by default', () => {
const logger = createLogger({});

logger.error('error', 1, 2);
expect(consoleError).toHaveBeenCalledWith(timestamp, 'error', '1', '2');

logger.warn('warning', 1, 2);
expect(consoleWarn).toHaveBeenCalledWith(timestamp, 'warning', '1', '2');

logger.info('message', 1, 2);
expect(consoleInfo).toHaveBeenCalledWith(timestamp, 'message', '1', '2');

logger.debug('data', 1, 2);
expect(consoleDebug).not.toHaveBeenCalled();
});

it('should use the log level from environment variables', () => {
process.env.LOG_LEVEL = 'debug';
const logger = createLogger({});

logger.error('error');
expect(consoleError).toHaveBeenCalledWith(timestamp, 'error');

logger.warn('warning');
expect(consoleWarn).toHaveBeenCalledWith(timestamp, 'warning');

logger.info('message');
expect(consoleInfo).toHaveBeenCalledWith(timestamp, 'message');

logger.debug('data');
expect(consoleDebug).toHaveBeenCalledWith(timestamp, 'data');
});

it('should use the log level from flags', () => {
process.env.LOG_LEVEL = 'debug';
const logger = createLogger({ logLevel: 'warn' });

logger.error('error');
expect(consoleError).toHaveBeenCalledWith(timestamp, 'error');

logger.warn('warning');
expect(consoleWarn).toHaveBeenCalledWith(timestamp, 'warning');

logger.info('message');
expect(consoleInfo).not.toHaveBeenCalled();

logger.debug('data');
expect(consoleDebug).not.toHaveBeenCalled();
});

it('should prefer the log level from options', () => {
process.env.LOG_LEVEL = 'debug';
const logger = createLogger({ logLevel: 'warn' }, { logLevel: 'error' });

logger.error('error');
expect(consoleError).toHaveBeenCalledWith(timestamp, 'error');

logger.warn('warning');
expect(consoleWarn).not.toHaveBeenCalled();

logger.info('message');
expect(consoleInfo).not.toHaveBeenCalled();

logger.debug('data');
expect(consoleDebug).not.toHaveBeenCalled();
});

it('should respect DISABLE_LOGGING regardless of logLevel flag or option', () => {
process.env.DISABLE_LOGGING = 'true';
process.env.LOG_LEVEL = 'debug';
const logger = createLogger({ logLevel: 'warn' }, { logLevel: 'error' });
logger.error('error');
expect(consoleError).not.toHaveBeenCalled();
});
});
10 changes: 8 additions & 2 deletions node-src/lib/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ interface QueueMessage {
messages: string[];
}

const { DISABLE_LOGGING, LOG_LEVEL = '', LOG_PREFIX } = process.env;
const LOG_LEVELS = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
const DEFAULT_LEVEL = 'info';

Expand All @@ -24,13 +23,18 @@ process.on('unhandledRejection', handleRejection);
const logInteractive = (args: any[]): string[] =>
args
.map((argument) => (argument && argument.message) || argument)
// .map((argument) => (typeof argument === 'number' ? String(argument) : argument))
.filter((argument) => typeof argument === 'string');

// Stringifies metadata to JSON
const logVerbose = (type: string, args: any[]) => {
const stringify =
type === 'error' ? (err: any) => JSON.stringify(errorSerializer(err)) : JSON.stringify;
return args.map((argument) => (typeof argument === 'string' ? argument : stringify(argument)));
return args.map((argument) =>
typeof argument === 'string' || typeof argument === 'number'
? String(argument)
: stringify(argument)
);
};

// Generate a timestamp like "14:30:00.123" in local time
Expand Down Expand Up @@ -114,6 +118,8 @@ const fileLogger = {

/* eslint-disable-next-line complexity */
export const createLogger = (flags: Flags, options?: Partial<Options>) => {
const { DISABLE_LOGGING, LOG_LEVEL = '', LOG_PREFIX } = process.env;

let level =
options?.logLevel ||
flags.logLevel ||
Expand Down

0 comments on commit 9bd481b

Please sign in to comment.