Skip to content

Instantly share code, notes, and snippets.

@juliusmarminge
Created July 13, 2023 11:44
Show Gist options
  • Save juliusmarminge/67081c41e857a7ebbf9484b829487171 to your computer and use it in GitHub Desktop.
Save juliusmarminge/67081c41e857a7ebbf9484b829487171 to your computer and use it in GitHub Desktop.
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument */
import chalk from 'chalk'
interface Logger {
debug(message: string, ...optionalParameters: any[]): void
info(message: string, ...optionalParameters: any[]): void
warn(message: string, ...optionalParameters: any[]): void
error(message: string, ...optionalParameters: any[]): void
[x: string]: any
}
const levels = ['debug', 'info', 'warn', 'error'] as const
export type LogLevels = (typeof levels)[number]
const colorize = (level: LogLevels, message: string) => {
switch (level) {
case 'debug': {
return chalk.bgCyan(chalk.bold('[ DEBUG ]')) + ' ' + chalk.cyan(message)
}
case 'info': {
return chalk.bgWhite(chalk.bold('[ INFO ]')) + ' ' + chalk.white(message)
}
case 'warn': {
return (
chalk.bgYellow(chalk.bold('[ WARN ]')) + ' ' + chalk.yellow(message)
)
}
case 'error': {
return chalk.bgRed(chalk.bold('[ ERROR ]')) + ' ' + chalk.red(message)
}
default: {
return message
}
}
}
class Logger implements Logger {
private subscriptions: {
fn: (m: { message: string; level: LogLevels; ts: number }) => void
level: LogLevels
}[]
constructor() {
this.subscriptions = []
}
debug(message: string | Error | unknown, ...optionalParameters: any[]) {
if (message instanceof Error) {
this.log('debug', message.message, [
optionalParameters,
message.stack,
message.cause,
])
} else if (typeof message === 'string') {
this.log('debug', message, optionalParameters)
} else {
this.log('debug', JSON.stringify(message), optionalParameters)
}
}
info(message: string | Error | unknown, ...optionalParameters: any[]) {
if (message instanceof Error) {
this.log('info', message.message, [
optionalParameters,
message.stack,
message.cause,
])
} else if (typeof message === 'string') {
this.log('info', message, optionalParameters)
} else {
this.log('info', JSON.stringify(message), optionalParameters)
}
}
warn(message: string | Error | unknown, ...optionalParameters: any[]) {
if (message instanceof Error) {
this.log('warn', message.message, [
optionalParameters,
message.stack,
message.cause,
])
} else if (typeof message === 'string') {
this.log('warn', message, optionalParameters)
} else {
this.log('warn', JSON.stringify(message), optionalParameters)
}
}
error(message: string | Error | unknown, ...optionalParameters: any[]) {
if (message instanceof Error) {
this.log('error', message.message, [
optionalParameters,
message.stack,
message.cause,
])
} else if (typeof message === 'string') {
this.log('error', message, optionalParameters)
} else {
this.log('error', JSON.stringify(message), optionalParameters)
}
}
subscribe(
function_: (m: { message: string; level: LogLevels; ts: number }) => void,
level?: LogLevels,
) {
if (!level) level = 'info'
this.subscriptions.push({ fn: function_, level })
}
unsubscribe(
function_: (m: { message: string; level: LogLevels; ts: number }) => void,
) {
this.subscriptions = this.subscriptions.filter(
({ fn: subFunction }) => subFunction !== function_,
)
}
private log(level: LogLevels, message: string, optionalParameters: any[]) {
const ts = Date.now()
const defaultLevel = 'info'
if (getLogLevels(defaultLevel).includes(level)) {
console[level](colorize(level, message), ...optionalParameters)
}
for (const { fn, level: subLevel } of this.subscriptions) {
if (getLogLevels(subLevel).includes(level)) fn({ message, level, ts })
}
}
}
// get all log levels above and including the given level
const getLogLevels = (level: LogLevels): LogLevels[] => {
return levels.slice(levels.indexOf(level))
}
export const logger = new Logger()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment