-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: added basic logger * build: run ci on any branch * build: run ci on push
- Loading branch information
Showing
11 changed files
with
340 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { BaseError } from './base-error'; | ||
|
||
/** | ||
* An error thrown when a function is called with invalid arguments. | ||
*/ | ||
export class ArgumentError extends BaseError { | ||
public readonly name = ArgumentError.name; | ||
|
||
/** | ||
* Instantiates the error. | ||
* | ||
* @param message A message which describes the error. | ||
* @param value The value of the invalid argument. | ||
* @param cause The underlying error. | ||
*/ | ||
constructor(message: string, public value: unknown, cause?: Error) { | ||
super(message, cause); | ||
|
||
Object.setPrototypeOf(this, ArgumentError.prototype); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* A base error which takes a cause. | ||
*/ | ||
export class BaseError extends Error { | ||
public readonly name = BaseError.name; | ||
|
||
/** | ||
* Instantiates an error. | ||
* | ||
* @param messsage Describes the error. | ||
* @param cause The underlying cause of the error. | ||
*/ | ||
constructor(messsage: string, public cause: Error) { | ||
super(messsage); | ||
|
||
Object.setPrototypeOf(this, BaseError.prototype); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
packages/nde-erfgoed-core/lib/logging/console-logger.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { ConsoleLogger } from './console-logger'; | ||
import { LoggerLevel } from './logger-level'; | ||
|
||
describe('ConsoleLogger', () => { | ||
let service: ConsoleLogger; | ||
|
||
beforeEach(async () => { | ||
service = new ConsoleLogger(LoggerLevel.silly, LoggerLevel.silly); | ||
}); | ||
|
||
afterEach(() => { | ||
// clear spies | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('should be correctly instantiated', () => { | ||
expect(service).toBeTruthy(); | ||
}); | ||
|
||
describe('log', () => { | ||
|
||
const levels = [ 'info', 'debug', 'warn', 'error' ]; | ||
|
||
it('LoggerLevel.silly should call console.log', () => { | ||
const consoleSpy = jest.spyOn(console, 'log'); | ||
service.log(LoggerLevel.silly, 'TestService', 'test message', 'data'); | ||
expect(consoleSpy).toHaveBeenCalled(); | ||
}); | ||
|
||
for (const level of levels) { | ||
if (level) { | ||
it(`LoggerLevel.${level} should call console.${level}`, () => { | ||
const consoleSpy = jest.spyOn(console, level as any); | ||
service.log(LoggerLevel[level], 'TestService', 'test message', 'data'); | ||
expect(consoleSpy).toHaveBeenCalled(); | ||
}); | ||
} | ||
} | ||
|
||
const params = { | ||
level: LoggerLevel.info, | ||
typeName: ' TestService', | ||
message: 'test message', | ||
}; | ||
const args = Object.keys(params); | ||
args.forEach((argument) => { | ||
it(`should throw error when ${argument} is null or undefined`, () => { | ||
const testArgs = args.map((arg) => arg === argument ? null : arg); | ||
expect(() => service.log.apply(service.log, testArgs)) | ||
.toThrow(`${argument} should be set`); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('level logs', () => { | ||
|
||
const levels = [ 'info', 'debug', 'warn', 'error' ]; | ||
|
||
for (const level of levels) { | ||
if (level) { | ||
it(`should log a ${level} message`, () => { | ||
const loggerSpy = jest.spyOn(service, 'log'); | ||
if (level === 'error') { | ||
service[level]('TestService', 'test message', 'test error', 'error'); | ||
expect(loggerSpy).toHaveBeenCalledWith(LoggerLevel.error, 'TestService', 'test message', { error: 'test error', caught: 'error' }); | ||
} else { | ||
service[level]('TestService', 'test message', 'test data'); | ||
expect(loggerSpy).toHaveBeenCalledWith(LoggerLevel[level], 'TestService', 'test message', 'test data'); | ||
} | ||
}); | ||
|
||
// test arguments for null or undefined | ||
const params = { | ||
level: LoggerLevel.info, | ||
typeName: ' TestService', | ||
}; | ||
const args = Object.keys(params); | ||
args.forEach((argument) => { | ||
it(`should throw error when ${argument} is null or undefined`, () => { | ||
const testArgs = args.map((arg) => arg === argument ? null : arg); | ||
expect(() => service.log.apply(service[level], testArgs)) | ||
.toThrow(`${argument} should be set`); | ||
}); | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* eslint-disable no-console -- this is a logger service */ | ||
|
||
import { ArgumentError } from '../errors/argument-error'; | ||
import { Logger } from './logger'; | ||
import { LoggerLevel } from './logger-level'; | ||
|
||
/** | ||
* JavaScript console-based logger service | ||
*/ | ||
export class ConsoleLogger extends Logger { | ||
|
||
/** | ||
* Instantiates the logger. | ||
* | ||
* @param minimumLevel The minimum level of a log to be printed. | ||
* @param minimumLevelPrintData The minimum level of a log for data to be printed. | ||
*/ | ||
constructor( | ||
protected readonly minimumLevel: LoggerLevel, | ||
protected readonly minimumLevelPrintData: LoggerLevel, | ||
) { | ||
super(minimumLevel, minimumLevelPrintData); | ||
} | ||
|
||
/** | ||
* Logs a message | ||
* | ||
* @param level Severity level of the log | ||
* @param typeName The location of the log | ||
* @param message Message that should be logged | ||
* @param data Any relevant data that should be logged | ||
*/ | ||
log(level: LoggerLevel, typeName: string, message: string, data?: any) { | ||
if (level === null || level === undefined) { | ||
throw new ArgumentError('level should be set', typeName); | ||
} | ||
|
||
if (!typeName) { | ||
throw new ArgumentError('typeName should be set', typeName); | ||
} | ||
|
||
if (!message) { | ||
throw new ArgumentError('message should be set', message); | ||
} | ||
|
||
const timestamp: string = new Date().toISOString(); | ||
|
||
if (level <= this.minimumLevel) { | ||
const logMessage = `[${timestamp} ${typeName}] ${message}`; | ||
const logData = level >= this.minimumLevelPrintData ? '' : data||''; | ||
const log = [ logMessage, logData ]; | ||
switch (level) { | ||
|
||
case LoggerLevel.info: | ||
console.info(...log); | ||
break; | ||
|
||
case LoggerLevel.debug: | ||
console.debug(...log); | ||
break; | ||
|
||
case LoggerLevel.warn: | ||
console.warn(...log); | ||
break; | ||
|
||
case LoggerLevel.error: | ||
console.error(...log); | ||
break; | ||
|
||
default: | ||
console.log(...log); | ||
break; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* Level of log severity based on node.js' | ||
*/ | ||
export enum LoggerLevel { | ||
error = 0, | ||
warn = 1, | ||
info = 2, | ||
http = 3, | ||
verbose = 4, | ||
debug = 5, | ||
silly = 6, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* eslint-disable no-console -- this is a logger service */ | ||
|
||
import { ArgumentError } from '../errors/argument-error'; | ||
import { LoggerLevel } from './logger-level'; | ||
|
||
/** | ||
* An abstract definition of a logger. | ||
*/ | ||
export abstract class Logger { | ||
|
||
/** | ||
* Instantiates the logger. | ||
* | ||
* @param minimumLevel The minimum level of a log to be printed. | ||
* @param minimumLevelPrintData The minimum level of a log for data to be printed. | ||
*/ | ||
constructor( | ||
protected readonly minimumLevel: LoggerLevel, | ||
protected readonly minimumLevelPrintData: LoggerLevel, | ||
) {} | ||
|
||
/** | ||
* Logs an info message | ||
* | ||
* @param typeName The location of the log | ||
* @param message Message that should be logged | ||
* @param data Any relevant data that should be logged | ||
*/ | ||
info(typeName: string, message: string, data?: any) { | ||
if (!typeName) { | ||
throw new ArgumentError('Typename should be set', typeName); | ||
} | ||
|
||
if (!message) { | ||
throw new ArgumentError('Message should be set', message); | ||
} | ||
|
||
this.log(LoggerLevel.info, typeName, message, data); | ||
} | ||
|
||
/** | ||
* Logs a debug message | ||
* | ||
* @param typeName The location of the log | ||
* @param message Message that should be logged | ||
* @param data Any relevant data that should be logged | ||
*/ | ||
debug(typeName: string, message: string, data?: any) { | ||
if (!typeName) { | ||
throw new ArgumentError('Typename should be set', typeName); | ||
} | ||
|
||
if (!message) { | ||
throw new ArgumentError('Message should be set', message); | ||
} | ||
|
||
this.log(LoggerLevel.debug, typeName, message, data); | ||
} | ||
|
||
/** | ||
* Logs a warning message | ||
* | ||
* @param typeName The location of the log | ||
* @param message Message that should be logged | ||
* @param data Any relevant data that should be logged | ||
*/ | ||
warn(typeName: string, message: string, data?: any) { | ||
if (!typeName) { | ||
throw new ArgumentError('Typename should be set', typeName); | ||
} | ||
|
||
if (!message) { | ||
throw new ArgumentError('Message should be set', message); | ||
} | ||
|
||
this.log(LoggerLevel.warn, typeName, message, data); | ||
} | ||
|
||
/** | ||
* Logs an error message | ||
* | ||
* @param typeName The location of the log | ||
* @param message Message that should be logged | ||
* @param error The error that was thrown | ||
* @param caught The error that was caught | ||
*/ | ||
error(typeName: string, message: string, error?: Error | any, caught?: any) { | ||
if (!typeName) { | ||
throw new ArgumentError('Typename should be set', typeName); | ||
} | ||
|
||
if (!message) { | ||
throw new ArgumentError('Message should be set', message); | ||
} | ||
|
||
this.log(LoggerLevel.error, typeName, message, { error, caught }); | ||
} | ||
|
||
/** | ||
* Logs a message | ||
* | ||
* @param level Severity level of the log | ||
* @param typeName The location of the log | ||
* @param message Message that should be logged | ||
* @param data Any relevant data that should be logged | ||
*/ | ||
abstract log(level: LoggerLevel, typeName: string, message: string, data?: any): void; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.