diff --git a/packages/logger/src/ILoggerFactory.ts b/packages/logger/src/ILoggerFactory.ts deleted file mode 100644 index d02f43e..0000000 --- a/packages/logger/src/ILoggerFactory.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {ILogger} from './logger/ILogger' - -export interface ILoggerFactory { - getLogger(name: string): ILogger -} diff --git a/packages/logger/src/LogLevel.ts b/packages/logger/src/LogLevel.ts index ac0b3e9..02dda1f 100644 --- a/packages/logger/src/LogLevel.ts +++ b/packages/logger/src/LogLevel.ts @@ -8,5 +8,6 @@ export enum LogLevel { } export function isLogLevel(value: string): value is keyof typeof LogLevel { - return LogLevel.hasOwnProperty(value) && isNaN(Number(value)) + return Object.prototype.hasOwnProperty + .call(LogLevel, value) && isNaN(Number(value)) } diff --git a/packages/logger/src/LoggerFactory.ts b/packages/logger/src/LoggerFactory.ts index 14f6d63..5c40ff1 100644 --- a/packages/logger/src/LoggerFactory.ts +++ b/packages/logger/src/LoggerFactory.ts @@ -1,66 +1,5 @@ -import { MessageFormatter } from './formatters' -import { getDefaultParams } from './getDefaultParams' -import { ILoggerFactory } from './ILoggerFactory' -import { ILogger, Logger } from './logger' -import { isLogLevel, LogLevel } from './LogLevel' -import { ConsoleTransport } from './transports' +import {Logger} from './logger/Logger' -// logging can be configured via environment variables, for example: -// `LOG='*:info,api:debug,-sql' node ...` sets all logs to info, api to debug, -// and disable all sql logs. - -export interface IEnabledLoggers { - readonly [key: string]: LogLevel -} - -export interface ILoggerOptions { - readonly enabledLoggers: IEnabledLoggers -} - -export class LoggerFactory implements ILoggerFactory { - - protected readonly defaultLogLevel: LogLevel - protected readonly loggers: {[key: string]: ILogger} = {} - getCorrelationId: () => string = () => '' - - static init({ - logs = getDefaultParams(), - } = {}) { - const enabledLoggers = logs.split(',').reduce((logConfig, log) => { - const [key, value] = log.split(':') - const level = value && value.toUpperCase() - logConfig[key] = isLogLevel(level) ? LogLevel[level] : LogLevel.INFO - return logConfig - }, {} as {[key: string]: LogLevel}) - - return new this({enabledLoggers}) - } - - constructor(readonly options: ILoggerOptions) { - this.defaultLogLevel = options.enabledLoggers['*'] || LogLevel.OFF - } - - getLoggerLevel(name: string): LogLevel { - const {enabledLoggers} = this.options - const disabled = !!enabledLoggers['-' + name] - if (disabled) { - return LogLevel.OFF - } - return enabledLoggers[name] || this.defaultLogLevel - } - - getLogger = (name: string): ILogger => { - if (this.loggers[name]) { - return this.loggers[name] - } - - const level = this.getLoggerLevel(name) - const logger = this.loggers[name] = new Logger({ - name, - formatters: [new MessageFormatter()], - transports: [new ConsoleTransport(level)], - }) - - return logger - } +export interface LoggerFactory { + getLogger(name: string): Logger } diff --git a/packages/logger/src/IMessage.ts b/packages/logger/src/Message.ts similarity index 71% rename from packages/logger/src/IMessage.ts rename to packages/logger/src/Message.ts index 8fdeb06..abd5655 100644 --- a/packages/logger/src/IMessage.ts +++ b/packages/logger/src/Message.ts @@ -1,9 +1,9 @@ import { LogLevel } from './LogLevel' -export interface IMessage { +export interface Message { loggerName: string level: LogLevel timestamp: Date message: string - params: any[] + params: unknown[] } diff --git a/packages/logger/src/LoggerFactory.test.ts b/packages/logger/src/SimpleLoggerFactory.test.ts similarity index 85% rename from packages/logger/src/LoggerFactory.test.ts rename to packages/logger/src/SimpleLoggerFactory.test.ts index a361805..779be0f 100644 --- a/packages/logger/src/LoggerFactory.test.ts +++ b/packages/logger/src/SimpleLoggerFactory.test.ts @@ -1,11 +1,12 @@ import stdMocks from 'std-mocks' -import loggerFactory, { LoggerFactory } from './' +import loggerFactory from './' +import { SimpleLoggerFactory } from './SimpleLoggerFactory' -describe('LoggerFactory', () => { +describe('SimpleLoggerFactory', () => { - let getLogger: typeof LoggerFactory.prototype.getLogger + let getLogger: typeof SimpleLoggerFactory.prototype.getLogger beforeEach(() => { - getLogger = LoggerFactory.init({ + getLogger = SimpleLoggerFactory.init({ logs: 'test1:verbose,-test3,t4,logtest5', }) .getLogger @@ -73,10 +74,10 @@ describe('LoggerFactory', () => { describe('create', () => { it('creates a logger with defaults', () => { - LoggerFactory.init() + SimpleLoggerFactory.init() }) it('logs all', () => { - const l = LoggerFactory.init({ logs: '*' }).getLogger('test') + const l = SimpleLoggerFactory.init({ logs: '*' }).getLogger('test') l.info('test info') l.debug('test debug') expect((global.console.debug as any).mock.calls).toEqual([]) diff --git a/packages/logger/src/SimpleLoggerFactory.ts b/packages/logger/src/SimpleLoggerFactory.ts new file mode 100644 index 0000000..38968d1 --- /dev/null +++ b/packages/logger/src/SimpleLoggerFactory.ts @@ -0,0 +1,66 @@ +import { MessageFormatter } from './formatters' +import { getDefaultParams } from './getDefaultParams' +import { LoggerFactory } from './LoggerFactory' +import { SimpleLogger, Logger } from './logger' +import { isLogLevel, LogLevel } from './LogLevel' +import { ConsoleTransport } from './transports' + +// logging can be configured via environment variables, for example: +// `LOG='*:info,api:debug,-sql' node ...` sets all logs to info, api to debug, +// and disable all sql logs. + +export interface EnabledLoggers { + readonly [key: string]: LogLevel +} + +export interface LoggerOptions { + readonly enabledLoggers: EnabledLoggers +} + +export class SimpleLoggerFactory implements LoggerFactory { + + protected readonly defaultLogLevel: LogLevel + protected readonly loggers: {[key: string]: Logger} = {} + getCorrelationId: () => string = () => '' + + static init({ + logs = getDefaultParams(), + } = {}) { + const enabledLoggers = logs.split(',').reduce((logConfig, log) => { + const [key, value] = log.split(':') + const level = value && value.toUpperCase() + logConfig[key] = isLogLevel(level) ? LogLevel[level] : LogLevel.INFO + return logConfig + }, {} as {[key: string]: LogLevel}) + + return new this({enabledLoggers}) + } + + constructor(readonly options: LoggerOptions) { + this.defaultLogLevel = options.enabledLoggers['*'] || LogLevel.OFF + } + + getLoggerLevel(name: string): LogLevel { + const {enabledLoggers} = this.options + const disabled = !!enabledLoggers['-' + name] + if (disabled) { + return LogLevel.OFF + } + return enabledLoggers[name] || this.defaultLogLevel + } + + getLogger = (name: string): Logger => { + if (this.loggers[name]) { + return this.loggers[name] + } + + const level = this.getLoggerLevel(name) + const logger = this.loggers[name] = new SimpleLogger({ + name, + formatters: [new MessageFormatter()], + transports: [new ConsoleTransport(level)], + }) + + return logger + } +} diff --git a/packages/logger/src/formatters/Formatter.ts b/packages/logger/src/formatters/Formatter.ts new file mode 100644 index 0000000..3a06f42 --- /dev/null +++ b/packages/logger/src/formatters/Formatter.ts @@ -0,0 +1,5 @@ +import { Message } from '../Message' + +export interface Formatter { + format(message: Message): Message +} diff --git a/packages/logger/src/formatters/IFormatter.ts b/packages/logger/src/formatters/IFormatter.ts deleted file mode 100644 index 25e34f4..0000000 --- a/packages/logger/src/formatters/IFormatter.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { IMessage } from '../IMessage' - -export interface IFormatter { - format(message: IMessage): IMessage -} diff --git a/packages/logger/src/formatters/MessageFormatter.ts b/packages/logger/src/formatters/MessageFormatter.ts index 8492fd8..b775240 100644 --- a/packages/logger/src/formatters/MessageFormatter.ts +++ b/packages/logger/src/formatters/MessageFormatter.ts @@ -1,5 +1,5 @@ -import { IFormatter } from './IFormatter' -import { IMessage } from '../IMessage' +import { Formatter } from './Formatter' +import { Message } from '../Message' import { LogLevel } from '../LogLevel' import { format } from 'util' @@ -13,8 +13,8 @@ function padleft(str: string, len: number) { return str } -export class MessageFormatter implements IFormatter { - format(message: IMessage) { +export class MessageFormatter implements Formatter { + format(message: Message) { message.message = format( '%s %s %s', message.loggerName, diff --git a/packages/logger/src/formatters/index.ts b/packages/logger/src/formatters/index.ts index a06ed59..e78282e 100644 --- a/packages/logger/src/formatters/index.ts +++ b/packages/logger/src/formatters/index.ts @@ -1,2 +1,2 @@ -export * from './IFormatter' +export * from './Formatter' export * from './MessageFormatter' diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts index 2bdb2a0..5e2b511 100644 --- a/packages/logger/src/index.ts +++ b/packages/logger/src/index.ts @@ -1,11 +1,11 @@ -export * from './ILoggerFactory' -export * from './IMessage' +export * from './LoggerFactory' +export * from './Message' export * from './LogLevel' export * from './Logger' export * from './LoggerFactory' -import {LoggerFactory} from './LoggerFactory' -export default LoggerFactory.init() +import {SimpleLoggerFactory} from './SimpleLoggerFactory' +export default SimpleLoggerFactory.init() import * as transports from './transports' export {transports} diff --git a/packages/logger/src/logger/ILogger.ts b/packages/logger/src/logger/ILogger.ts deleted file mode 100644 index 132b1a6..0000000 --- a/packages/logger/src/logger/ILogger.ts +++ /dev/null @@ -1,9 +0,0 @@ -type ILogFunction = (message: string, ...meta: any[]) => void - -export interface ILogger { - error: ILogFunction - warn: ILogFunction - info: ILogFunction - debug: ILogFunction - verbose: ILogFunction -} diff --git a/packages/logger/src/logger/Logger.ts b/packages/logger/src/logger/Logger.ts index 85656ef..65f4375 100644 --- a/packages/logger/src/logger/Logger.ts +++ b/packages/logger/src/logger/Logger.ts @@ -1,51 +1,9 @@ -import { IFormatter } from '../formatters' -import { IMessage } from '../IMessage' -import { LogLevel } from '../LogLevel' -import { ITransport } from '../transports' -import { ILogger } from './ILogger' +type ILogFunction = (message: string, ...meta: unknown[]) => void -interface ILoggerParams { - name: string - readonly formatters: readonly IFormatter[], - readonly transports: readonly ITransport[], -} - -export class Logger implements ILogger { - constructor(protected readonly config: ILoggerParams) {} - - protected log(level: LogLevel, message: string, params: any[]) { - const initialMessage: IMessage = { - loggerName: this.config.name, - timestamp: new Date(), - message, - params, - level, - } - const formattedMessage = this.config.formatters.reduce((m, f) => { - return f.format(m) - }, initialMessage) - - this.config.transports.forEach(t => { - if (formattedMessage.level <= t.level) { - t.write(formattedMessage) - } - }) - } - - error(message: string, ...args: any[]) { - this.log(LogLevel.ERROR, message, args) - } - warn(message: string, ...args: any[]) { - this.log(LogLevel.WARN, message, args) - - } - info(message: string, ...args: any[]) { - this.log(LogLevel.INFO, message, args) - } - debug(message: string, ...args: any[]) { - this.log(LogLevel.DEBUG, message, args) - } - verbose(message: string, ...args: any[]) { - this.log(LogLevel.VERBOSE, message, args) - } +export interface Logger { + error: ILogFunction + warn: ILogFunction + info: ILogFunction + debug: ILogFunction + verbose: ILogFunction } diff --git a/packages/logger/src/logger/SimpleLogger.ts b/packages/logger/src/logger/SimpleLogger.ts new file mode 100644 index 0000000..d0fd556 --- /dev/null +++ b/packages/logger/src/logger/SimpleLogger.ts @@ -0,0 +1,50 @@ +import { Formatter } from '../formatters' +import { Message } from '../Message' +import { LogLevel } from '../LogLevel' +import { Transport } from '../transports' +import { Logger } from './Logger' + +interface LoggerParams { + name: string + readonly formatters: readonly Formatter[] + readonly transports: readonly Transport[] +} + +export class SimpleLogger implements Logger { + constructor(protected readonly config: LoggerParams) {} + + protected log(level: LogLevel, message: string, params: unknown[]) { + const initialMessage: Message = { + loggerName: this.config.name, + timestamp: new Date(), + message, + params, + level, + } + const formattedMessage = this.config.formatters.reduce((m, f) => { + return f.format(m) + }, initialMessage) + + this.config.transports.forEach(t => { + if (formattedMessage.level <= t.level) { + t.write(formattedMessage) + } + }) + } + + error(message: string, ...args: unknown[]) { + this.log(LogLevel.ERROR, message, args) + } + warn(message: string, ...args: unknown[]) { + this.log(LogLevel.WARN, message, args) + } + info(message: string, ...args: unknown[]) { + this.log(LogLevel.INFO, message, args) + } + debug(message: string, ...args: unknown[]) { + this.log(LogLevel.DEBUG, message, args) + } + verbose(message: string, ...args: unknown[]) { + this.log(LogLevel.VERBOSE, message, args) + } +} diff --git a/packages/logger/src/logger/index.ts b/packages/logger/src/logger/index.ts index 625f6ac..0fff30e 100644 --- a/packages/logger/src/logger/index.ts +++ b/packages/logger/src/logger/index.ts @@ -1,2 +1,2 @@ -export * from './ILogger' export * from './Logger' +export * from './SimpleLogger' diff --git a/packages/logger/src/transports/ConsoleTransport.ts b/packages/logger/src/transports/ConsoleTransport.ts index 18a6f0b..3077e04 100644 --- a/packages/logger/src/transports/ConsoleTransport.ts +++ b/packages/logger/src/transports/ConsoleTransport.ts @@ -1,11 +1,11 @@ -import { ITransport } from './ITransport' -import { IMessage } from '../IMessage' +import { Transport } from './Transport' +import { Message } from '../Message' import { LogLevel } from '../LogLevel' -export class ConsoleTransport implements ITransport { +export class ConsoleTransport implements Transport { constructor(readonly level: LogLevel) {} - write(entry: IMessage) { + write(entry: Message) { if (entry.level <= this.level) { switch (entry.level) { case LogLevel.ERROR: @@ -24,6 +24,7 @@ export class ConsoleTransport implements ITransport { case LogLevel.DEBUG: // tslint:disable-next-line console.debug(entry.message) + break case LogLevel.OFF: // do nothing } diff --git a/packages/logger/src/transports/ITransport.ts b/packages/logger/src/transports/ITransport.ts deleted file mode 100644 index 6601835..0000000 --- a/packages/logger/src/transports/ITransport.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IMessage } from '../IMessage' -import { LogLevel } from '../LogLevel' - -export interface ITransport { - readonly level: LogLevel - write(message: IMessage): void -} diff --git a/packages/logger/src/transports/Transport.ts b/packages/logger/src/transports/Transport.ts new file mode 100644 index 0000000..2b0fc62 --- /dev/null +++ b/packages/logger/src/transports/Transport.ts @@ -0,0 +1,7 @@ +import { Message } from '../Message' +import { LogLevel } from '../LogLevel' + +export interface Transport { + readonly level: LogLevel + write(message: Message): void +} diff --git a/packages/logger/src/transports/index.ts b/packages/logger/src/transports/index.ts index 714cc7e..76637b5 100644 --- a/packages/logger/src/transports/index.ts +++ b/packages/logger/src/transports/index.ts @@ -1,2 +1,2 @@ export * from './ConsoleTransport' -export * from './ITransport' +export * from './Transport'