@dexare/logger
Version:
A Dexare module that provides colorful logging
161 lines (142 loc) • 4.43 kB
text/typescript
import { DexareModule, DexareClient, LoggerExtra, BaseConfig } from 'dexare';
import winston, { format } from 'winston';
import dayjs from 'dayjs';
import chalk, { Chalk } from 'chalk';
import * as util from 'util';
export interface LoggerConfig extends BaseConfig {
logger?: LoggerModuleOptions;
}
export interface LoggerModuleOptions {
level?: string;
inspectOptions?: any;
}
const colorPool = [
chalk.black.bgCyan,
chalk.black.bgYellow,
chalk.black.bgRed,
chalk.black.bgGreen,
chalk.black.bgBlue,
chalk.black.bgMagenta,
chalk.black.bgGrey,
chalk.black.bgCyanBright,
chalk.black.bgYellowBright,
chalk.black.bgRedBright,
chalk.black.bgGreenBright,
chalk.black.bgBlueBright,
chalk.black.bgMagentaBright,
chalk.cyan.bgBlack,
chalk.yellow.bgBlack,
chalk.red.bgBlack,
chalk.green.bgBlack,
chalk.blue.bgBlack,
chalk.magenta.bgBlack,
chalk.grey.bgBlack,
chalk.cyanBright.bgBlack,
chalk.yellowBright.bgBlack,
chalk.redBright.bgBlack,
chalk.greenBright.bgBlack,
chalk.blueBright.bgBlack,
chalk.magentaBright.bgBlack
];
export default class LoggerModule<T extends DexareClient<LoggerConfig>> extends DexareModule<T> {
moduleColors: { [level: string]: Chalk } = {
dexare: chalk.black.bgRed,
eris: chalk.black.bgCyan,
commands: chalk.black.bgYellow,
sys: chalk.black.bgGray,
dbots: chalk.black.bgYellowBright
};
levelColors: { [level: string]: Chalk } = {
info: chalk.black.bgCyan,
warn: chalk.black.bgYellow,
error: chalk.black.bgRed,
debug: chalk.magenta.bgBlack
};
constructor(client: T) {
super(client, {
name: 'logger',
description: 'Colorful logging with the winston module'
});
this.client.logErisEvents();
this.filePath = __filename;
}
load() {
this.registerEvent('logger', this.onLog.bind(this));
}
unload() {
this.unregisterAllEvents();
}
get config() {
return this.client.config.logger;
}
private async onLog(_: unknown, level: string, moduleName: string, args: any[], extra?: LoggerExtra) {
if (!winston.loggers.has(moduleName))
winston.loggers.add(moduleName, {
format: format.combine(
format.printf((info) => {
const lClk = this.levelColors[info.level] || chalk.yellow.bgBlack;
const mClk =
this.moduleColors[moduleName] ||
colorPool[Math.abs(this._hashCode(moduleName)) % colorPool.length];
return (
mClk(` ${moduleName} `) +
chalk.black.bgWhite(` ${dayjs().format('MM/DD HH:mm:ss')} `) +
lClk(this._centrePad(info.level, 10)) +
(info.id !== undefined ? chalk.black.bgYellowBright(` ${info.id} `) : '') +
` ${info.message}`
);
})
),
transports: [
new winston.transports.Console({
level: this.config?.level || (process.env.NODE_ENV === 'production' ? 'info' : 'debug')
})
]
});
const text = [];
// Util formatting
if (typeof args[0] === 'string') {
const formats = args[0].match(/%[sdifjoO]/g);
if (formats) {
const a = args.splice(1, formats.length);
text.push(util.format(args.shift(), ...a));
} else text.push(chalk.white(args.shift()));
}
// Colorize the rest of the arguments
for (const arg of args) {
if (typeof arg === 'string') {
text.push(chalk.magenta(`'${arg}'`));
} else if (typeof arg === 'number') {
text.push(chalk.cyan(arg.toString()));
} else if (typeof arg === 'object') {
text.push('\n');
if (arg instanceof Error) {
text.push(chalk.red(arg.stack));
} else {
text.push(util.inspect(arg, this.config?.inspectOptions || {}));
}
} else text.push(arg);
}
winston.loggers.get(moduleName).log(level as any, text.join(' '), extra);
}
private _centrePad(text: string, length: number) {
if (text.length < length)
return (
' '.repeat(Math.floor((length - text.length) / 2)) +
text +
' '.repeat(Math.ceil((length - text.length) / 2))
);
else return text;
}
private _hashCode(str: string) {
var hash = 0,
i,
chr;
for (i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0;
}
return hash;
}
}