Skip to content

Commit

Permalink
feat: improve Logger (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyTseng authored Jan 25, 2024
1 parent 50f6094 commit eb3ce9b
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 87 deletions.
78 changes: 39 additions & 39 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
module.exports = {
root: true,
env: {
node: true,
root: true,
env: {
node: true,
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: ['plugin:@typescript-eslint/recommended'],
overrides: [
{
files: ['**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-array-constructor': 'off',
},
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: ['plugin:@typescript-eslint/recommended'],
overrides: [
{
files: ['**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-array-constructor': 'off',
},
{
files: ['**/*.spec.ts', 'integration/**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.spec.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-empty-function': 'off',
},
{
files: ['**/*.spec.ts', 'integration/**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-empty-function': 'off',
},
}
]
};
}
]
};
93 changes: 86 additions & 7 deletions packages/common/__test__/services/console-logger.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConsoleLoggerService } from '../../src/services';
import { LogLevel, ConsoleLoggerService } from '../../src';

describe('ConsoleLoggerService', () => {
let logger: ConsoleLoggerService;
Expand All @@ -7,16 +7,95 @@ describe('ConsoleLoggerService', () => {
logger = new ConsoleLoggerService();
});

describe('error', () => {
it('should log error', () => {
const context = 'test';
const error = new Error('error');
describe('setLogLevel', () => {
it('should set the log level', () => {
logger.setLogLevel(LogLevel.WARN);
expect((logger as any).logLevel).toEqual(LogLevel.WARN);
});
});

describe('debug', () => {
it('should log debug when log level is DEBUG', () => {
const consoleSpy = jest.spyOn(console, 'debug').mockImplementation();
logger.setLogLevel(LogLevel.DEBUG);
logger.debug('debug message');
expect(consoleSpy).toHaveBeenCalledWith('debug message');
});

it('should not log debug when log level is higher than DEBUG', () => {
const consoleSpy = jest.spyOn(console, 'debug').mockImplementation();
logger.setLogLevel(LogLevel.INFO);
logger.debug('debug message');
expect(consoleSpy).not.toHaveBeenCalled();
});
});

describe('info', () => {
it('should log info when log level is lower than INFO', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
logger.setLogLevel(LogLevel.DEBUG);
logger.info('info message');
expect(consoleSpy).toHaveBeenCalledWith('info message');
});

logger.error(context, error);
it('should log info when log level is INFO', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
logger.setLogLevel(LogLevel.INFO);
logger.info('info message');
expect(consoleSpy).toHaveBeenCalledWith('info message');
});

it('should not log info when log level is higher than INFO', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
logger.setLogLevel(LogLevel.WARN);
logger.info('info message');
expect(consoleSpy).not.toHaveBeenCalled();
});
});

describe('warn', () => {
it('should log warn when log level is lower than WARN', () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
logger.setLogLevel(LogLevel.INFO);
logger.warn('warn message');
expect(consoleSpy).toHaveBeenCalledWith('warn message');
});

it('should log warn when log level is WARN', () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
logger.setLogLevel(LogLevel.WARN);
logger.warn('warn message');
expect(consoleSpy).toHaveBeenCalledWith('warn message');
});

it('should not log warn when log level is higher than WARN', () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
logger.setLogLevel(LogLevel.ERROR);
logger.warn('warn message');
expect(consoleSpy).not.toHaveBeenCalled();
});
});

describe('error', () => {
it('should log error when log level is lower than ERROR', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
logger.setLogLevel(LogLevel.WARN);
logger.error('error message');
expect(consoleSpy).toHaveBeenCalledWith('error message');
});

it('should log error when log level is ERROR', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
logger.setLogLevel(LogLevel.ERROR);
logger.error('error message');
expect(consoleSpy).toHaveBeenCalledWith('error message');
});

expect(consoleSpy).toHaveBeenCalledWith(`[${context}]`, error);
it('should not log error when log level is higher than ERROR', () => {
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
logger.setLogLevel(LogLevel.ERROR);
logger.error('error message');
expect(consoleSpy).toHaveBeenCalledWith('error message');
});
});
});
1 change: 1 addition & 0 deletions packages/common/src/enums/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './client.enum';
export * from './event.enum';
export * from './log.enum';
export * from './message.enum';
6 changes: 6 additions & 0 deletions packages/common/src/enums/log.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
2 changes: 1 addition & 1 deletion packages/common/src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './client.interface';
export * from './common.interface';
export * from './event-respository.interface';
export * from './event-repository.interface';
export * from './event.interface';
export * from './filter.interface';
export * from './logger.interface';
Expand Down
8 changes: 7 additions & 1 deletion packages/common/src/interfaces/logger.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { LogLevel } from '../enums';

export interface Logger {
error(context: string, error: Error): void;
setLogLevel(level: LogLevel): void;
debug(message: string, ...args: any[]): void;
info(message: string, ...args: any[]): void;
warn(message: string, ...args: any[]): void;
error(message: string, ...args: any[]): void;
}
31 changes: 29 additions & 2 deletions packages/common/src/services/console-logger.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
import { LogLevel } from '../enums';
import { Logger } from '../interfaces';

export class ConsoleLoggerService implements Logger {
error(context: string, error: Error): void {
console.log(`[${context}]`, error);
private logLevel: LogLevel = LogLevel.INFO;

setLogLevel(level: LogLevel): void {
this.logLevel = level;
}

debug(...args: any[]): void {
if (this.logLevel <= LogLevel.DEBUG) {
console.debug(...args);
}
}

info(...args: any[]): void {
if (this.logLevel <= LogLevel.INFO) {
console.log(...args);
}
}

warn(...args: any[]): void {
if (this.logLevel <= LogLevel.WARN) {
console.warn(...args);
}
}

error(...args: any[]): void {
if (this.logLevel <= LogLevel.ERROR) {
console.error(...args);
}
}
}
21 changes: 15 additions & 6 deletions packages/core/__test__/services/event.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ClientContext,
ClientReadyState,
ConsoleLoggerService,
Event,
EventKind,
EventRepository,
Expand All @@ -25,17 +26,18 @@ describe('eventService', () => {
find: jest.fn(),
findOne: jest.fn(),
};
subscriptionService = new SubscriptionService(new Map());
subscriptionService = new SubscriptionService(
new Map(),
new ConsoleLoggerService(),
);
subscriptionService.broadcast = jest.fn();
pluginManagerService = new PluginManagerService();
eventService = new EventService(
eventRepository,
subscriptionService,
pluginManagerService,
new ConsoleLoggerService(),
{
logger: {
error: jest.fn(),
},
filterResultCacheTtl: 0,
},
);
Expand Down Expand Up @@ -79,6 +81,7 @@ describe('eventService', () => {
eventRepository,
subscriptionService,
pluginManagerService,
new ConsoleLoggerService(),
);
const filters = [{}, {}] as Filter[];
const events = [{ id: 'a' }, { id: 'b' }] as Event[];
Expand Down Expand Up @@ -207,13 +210,16 @@ describe('eventService', () => {
jest.spyOn(eventRepository, 'upsert').mockImplementation(() => {
throw new Error('test');
});
const spyLoggerError = jest
.spyOn(eventService['logger'], 'error')
.mockImplementation();

expect(await eventService.handleEvent(ctx, event)).toEqual({
success: false,
message: 'error: test',
});
expect(subscriptionService.broadcast).not.toHaveBeenCalled();
expect(eventService['logger'].error).toHaveBeenCalled();
expect(spyLoggerError).toHaveBeenCalled();
});

it('should catch unknown error', async () => {
Expand All @@ -222,13 +228,16 @@ describe('eventService', () => {
jest.spyOn(eventRepository, 'findOne').mockResolvedValue(null);
jest.spyOn(EventUtils, 'validate').mockReturnValue(undefined);
jest.spyOn(eventRepository, 'upsert').mockRejectedValue('unknown');
const spyLoggerError = jest
.spyOn(eventService['logger'], 'error')
.mockImplementation();

expect(await eventService.handleEvent(ctx, event)).toEqual({
success: false,
message: 'error: unknown',
});
expect(subscriptionService.broadcast).not.toHaveBeenCalled();
expect(eventService['logger'].error).toHaveBeenCalled();
expect(spyLoggerError).toHaveBeenCalled();
});
});

Expand Down
15 changes: 9 additions & 6 deletions packages/core/__test__/services/subscription.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Client,
ClientContext,
ClientReadyState,
ConsoleLoggerService,
Event,
EventUtils,
Filter,
Expand All @@ -17,11 +18,10 @@ describe('SubscriptionService', () => {

beforeEach(() => {
clientsMap = new Map<Client, ClientContext>();
subscriptionService = new SubscriptionService(clientsMap, {
logger: {
error: jest.fn(),
},
});
subscriptionService = new SubscriptionService(
clientsMap,
new ConsoleLoggerService(),
);
client = {
readyState: ClientReadyState.OPEN,
send: jest.fn(),
Expand Down Expand Up @@ -138,12 +138,15 @@ describe('SubscriptionService', () => {
jest.spyOn(EventUtils, 'isMatchingFilter').mockImplementation(() => {
throw new Error('error');
});
const spyLoggerError = jest
.spyOn(subscriptionService['logger'], 'error')
.mockImplementation();

subscriptionService.subscribe(ctx, subscriptionId, filters);
await subscriptionService.broadcast(event);

expect(client.send).not.toHaveBeenCalled();
expect(subscriptionService['logger'].error).toHaveBeenCalled();
expect(spyLoggerError).toHaveBeenCalled();
});
});
});
6 changes: 5 additions & 1 deletion packages/core/src/interfaces/handle-result.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Event, Logger, MessageType } from '@nostr-relay/common';
import { Event, LogLevel, Logger, MessageType } from '@nostr-relay/common';

/**
* Options for NostrRelay
Expand All @@ -13,6 +13,10 @@ export type NostrRelayOptions = {
* Logger to use. `Default: ConsoleLoggerService`
*/
logger?: Logger;
/**
* The minimum log level to log. `Default: LogLevel.INFO`
*/
logLevel?: LogLevel;
createdAtUpperLimit?: number;
createdAtLowerLimit?: number;
/**
Expand Down
Loading

0 comments on commit eb3ce9b

Please sign in to comment.