Refactor logger
This commit is contained in:
parent
c444a03884
commit
d2b58fac6f
@ -1,26 +1,78 @@
|
|||||||
import util from 'util';
|
import { format } from 'util';
|
||||||
|
|
||||||
type LogType = 'info' | 'debug' | 'warn' | 'error';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for all of Squeebot. Use this instead of console.log/warn/error!
|
* Log level
|
||||||
|
*/
|
||||||
|
export enum LogLevel {
|
||||||
|
INFO,
|
||||||
|
WARN,
|
||||||
|
ERROR,
|
||||||
|
DEBUG,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LogListener = (
|
||||||
|
ltype: LogLevel,
|
||||||
|
...data: any[]
|
||||||
|
) => void | Promise<void>;
|
||||||
|
|
||||||
|
export type ConsoleFunction = (...data: any[]) => void;
|
||||||
|
export type ConsoleLogFunction = ConsoleFunction;
|
||||||
|
export type ConsoleWarnFunction = ConsoleFunction;
|
||||||
|
export type ConsoleErrorFunction = ConsoleFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for all of Squeebot. Use this instead of console.log/warn/error in your plugins!
|
||||||
*/
|
*/
|
||||||
export class Logger {
|
export class Logger {
|
||||||
private console = [console.log, console.warn, console.error];
|
/**
|
||||||
|
* The `console.*` functions used for logging convenience.
|
||||||
|
*
|
||||||
|
* Defaults to `console.log`, `console.warn`, `console.error`.
|
||||||
|
*
|
||||||
|
* Can really be anything that accepts the input for `node:util.format`.
|
||||||
|
*/
|
||||||
|
public console: [
|
||||||
|
ConsoleLogFunction,
|
||||||
|
ConsoleWarnFunction,
|
||||||
|
ConsoleErrorFunction
|
||||||
|
] = [console.log, console.warn, console.error];
|
||||||
|
|
||||||
constructor(
|
/**
|
||||||
public timestamp = 'dd/mm/yy HH:MM:ss'
|
* External Logger log event listeners.
|
||||||
) {}
|
*/
|
||||||
|
protected listeners: LogListener[] = [];
|
||||||
|
|
||||||
public dateFmt(date: Date) {
|
constructor(public timestamp = 'dd/mm/yy HH:MM:ss') {}
|
||||||
return date.toISOString()
|
|
||||||
.replace(/T/, ' ')
|
public formatDate(date: Date): string {
|
||||||
.replace(/\..+/, '');
|
return date.toISOString().replace(/T/, ' ').replace(/\..+/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set node.js readline consideration
|
* Add a logger listener, useful for redirecting logger output somewhere else.
|
||||||
|
* Will not await any Promises but it will catch unhandled rejections - please do not depend on this.
|
||||||
|
* @param fn Log listener
|
||||||
|
*/
|
||||||
|
public listen(fn: LogListener): void {
|
||||||
|
this.listeners.push(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a logger listener.
|
||||||
|
* @param fn Log listener
|
||||||
|
* @returns nothing
|
||||||
|
*/
|
||||||
|
public unlisten(fn: LogListener): void {
|
||||||
|
const inx = this.listeners.indexOf(fn);
|
||||||
|
if (inx === -1) return;
|
||||||
|
this.listeners.splice(inx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set node.js readline consideration.
|
||||||
* @param rl Readline instance
|
* @param rl Readline instance
|
||||||
|
* @see Logger.console - the array modified by this function
|
||||||
|
* @see Logger.resetConsole - the "undo" to this function
|
||||||
*/
|
*/
|
||||||
public setReadline(rl: any): void {
|
public setReadline(rl: any): void {
|
||||||
for (const index in this.console) {
|
for (const index in this.console) {
|
||||||
@ -34,32 +86,41 @@ export class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write out to log
|
* Reset output consoles to default. Useful for dynamically detaching readline.
|
||||||
* @param ltype Logger level
|
* @see Logger.console
|
||||||
* @param data Data to log
|
|
||||||
*/
|
*/
|
||||||
private write(ltype: LogType, ...data: any[]): void {
|
public resetConsole() {
|
||||||
const message = [];
|
this.console = [console.log, console.warn, console.error];
|
||||||
let cfunc = this.console[0];
|
|
||||||
|
|
||||||
if (this.timestamp) {
|
|
||||||
message.push(`[${this.dateFmt(new Date())}]`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ltype) {
|
/**
|
||||||
case 'info':
|
* Write out to log
|
||||||
|
* @param logLevel Logger level
|
||||||
|
* @param data Data to log. Will be sent to `node:util.format`
|
||||||
|
* @see util.format
|
||||||
|
*/
|
||||||
|
public write(logLevel: LogLevel, ...data: any[]): void {
|
||||||
|
const message = [];
|
||||||
|
let outputFunction = this.console[0];
|
||||||
|
|
||||||
|
if (this.timestamp) {
|
||||||
|
message.push(`[${this.formatDate(new Date())}]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (logLevel) {
|
||||||
|
case LogLevel.INFO:
|
||||||
message.push('[ INFO]');
|
message.push('[ INFO]');
|
||||||
break;
|
break;
|
||||||
case 'debug':
|
case LogLevel.DEBUG:
|
||||||
message.push('[DEBUG]');
|
message.push('[DEBUG]');
|
||||||
break;
|
break;
|
||||||
case 'warn':
|
case LogLevel.WARN:
|
||||||
message.push('[ WARN]');
|
message.push('[ WARN]');
|
||||||
cfunc = this.console[1];
|
outputFunction = this.console[1];
|
||||||
break;
|
break;
|
||||||
case 'error':
|
case LogLevel.ERROR:
|
||||||
message.push('[ERROR]');
|
message.push('[ERROR]');
|
||||||
cfunc = this.console[2];
|
outputFunction = this.console[2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,10 +128,13 @@ export class Logger {
|
|||||||
let final = data[0];
|
let final = data[0];
|
||||||
if (data.length > 1) {
|
if (data.length > 1) {
|
||||||
const fargs = data.slice(1);
|
const fargs = data.slice(1);
|
||||||
final = util.format(data[0], ...fargs);
|
final = format(data[0], ...fargs);
|
||||||
}
|
}
|
||||||
message.push(final);
|
message.push(final);
|
||||||
cfunc(...message);
|
|
||||||
|
// Notify listeners and output
|
||||||
|
this.notify(logLevel, ...message);
|
||||||
|
outputFunction(...message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,7 +143,7 @@ export class Logger {
|
|||||||
* See `console.log` for more information.
|
* See `console.log` for more information.
|
||||||
*/
|
*/
|
||||||
public log(...data: any[]): void {
|
public log(...data: any[]): void {
|
||||||
this.write('info', ...data);
|
this.write(LogLevel.INFO, ...data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +152,7 @@ export class Logger {
|
|||||||
* See `console.warn` for more information.
|
* See `console.warn` for more information.
|
||||||
*/
|
*/
|
||||||
public warn(...data: any[]): void {
|
public warn(...data: any[]): void {
|
||||||
this.write('warn', ...data);
|
this.write(LogLevel.WARN, ...data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +161,7 @@ export class Logger {
|
|||||||
* See `console.log` for more information.
|
* See `console.log` for more information.
|
||||||
*/
|
*/
|
||||||
public info(...data: any[]): void {
|
public info(...data: any[]): void {
|
||||||
this.write('info', ...data);
|
this.write(LogLevel.INFO, ...data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +170,7 @@ export class Logger {
|
|||||||
* See `console.error` for more information.
|
* See `console.error` for more information.
|
||||||
*/
|
*/
|
||||||
public error(...data: any[]): void {
|
public error(...data: any[]): void {
|
||||||
this.write('error', ...data);
|
this.write(LogLevel.ERROR, ...data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +179,34 @@ export class Logger {
|
|||||||
* See `console.log` for more information.
|
* See `console.log` for more information.
|
||||||
*/
|
*/
|
||||||
public debug(...data: any[]): void {
|
public debug(...data: any[]): void {
|
||||||
this.write('debug', ...data);
|
this.write(LogLevel.DEBUG, ...data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify logger listeners about new lines. Catches uncaught errors.
|
||||||
|
* @param level Log level
|
||||||
|
* @param data Log data
|
||||||
|
*/
|
||||||
|
protected notify(level: LogLevel, ...data: any): void {
|
||||||
|
for (const listener of this.listeners) {
|
||||||
|
try {
|
||||||
|
const resp = listener.call(null, level, ...data);
|
||||||
|
// Catch Promise errors
|
||||||
|
if (resp instanceof Promise) {
|
||||||
|
resp.catch((err) =>
|
||||||
|
process.stderr.write(
|
||||||
|
`A Logger listener threw an unhandled rejection: ${err.stack}\r\n`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
process.stderr.write(
|
||||||
|
`A Logger listener threw an unhandled error: ${
|
||||||
|
(err as Error).stack
|
||||||
|
}\r\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user