You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/packages/hydrooj/src/logger.ts

78 lines
3.0 KiB
TypeScript

4 years ago
import { inspect, format } from 'util';
import { argv } from 'yargs';
4 years ago
import { Time } from './utils';
const instances: Record<string, Logger> = {};
type LogFunction = (format: any, ...param: any[]) => void
type LogType = 'success' | 'error' | 'info' | 'warn' | 'debug'
export interface Logger extends Record<LogType, LogFunction> { }
export class Logger {
static readonly SUCCESS = 1
static readonly ERROR = 1
static readonly INFO = 2
static readonly WARN = 2
static readonly DEBUG = 3
static baseLevel = argv.debug ? 3 : 2
static showDiff = false
static levels: Record<string, number> = {}
static lastTime = 0
static formatters: Record<string, (this: Logger, value: any) => string> = {
4 years ago
o: (value) => inspect(value).replace(/\s*\n\s*/g, ' '),
}
constructor(public name: string, private showDiff = false) {
if (name in instances) return instances[name];
let hash = 0;
for (let i = 0; i < name.length; i++) {
hash = ((hash << 3) - hash) + name.charCodeAt(i);
hash |= 0;
}
instances[name] = this;
this.createMethod('success', '[S] ', Logger.SUCCESS);
this.createMethod('error', '[E] ', Logger.ERROR);
this.createMethod('info', '[I] ', Logger.INFO);
this.createMethod('warn', '[W] ', Logger.WARN);
this.createMethod('debug', '[D] ', Logger.DEBUG);
}
private createMethod(name: LogType, prefix: string, minLevel: number) {
this[name] = (...args: [any, ...any[]]) => {
if (this.level < minLevel) return;
4 years ago
const msg = `${prefix} ${this.name} ${this.format(...args)}`;
if (process.send) process.send({ event: 'message/log', payload: [msg] });
else global.Hydro.service.bus.parallel('message/log', msg);
};
}
get level() {
return Logger.levels[this.name] ?? Logger.baseLevel;
}
extend = (namespace: string, showDiff = this.showDiff) => new Logger(`${this.name}:${namespace}`, showDiff)
format: (format: any, ...param: any[]) => string = (...args) => {
if (args[0] instanceof Error) args[0] = args[0].stack || args[0].message;
else if (typeof args[0] !== 'string') args.unshift('%O');
let index = 0;
args[0] = (args[0] as string).replace(/%([a-zA-Z%])/g, (match, fmt) => {
if (match === '%%') return '%';
index += 1;
const formatter = Logger.formatters[fmt];
if (typeof formatter === 'function') {
match = formatter.call(this, args[index]);
args.splice(index, 1);
index -= 1;
}
return match;
}).split('\n').join('\n ');
if (Logger.showDiff || this.showDiff) {
const now = Date.now();
4 years ago
if (Logger.lastTime) args.push(`+${Time.formatTimeShort(now - Logger.lastTime)}`);
Logger.lastTime = now;
}
return format(...args);
}
}
4 years ago
global.Hydro.Logger = Logger;