all repos — stealth-developers @ eb45bf91d07a587e564849ea7fe7e87c12de47c4

apps/bot/src/lib/logger.ts (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
import { type ILogger, LogLevel } from "@sapphire/framework";
import pino, { type Logger as PinoInstance } from "pino";
import config from "@stealth-developers/config";

export class PinoSapphireLogger implements ILogger {
	private pino: PinoInstance;
	private minLevel: LogLevel;

	constructor(options?: pino.LoggerOptions, minLevel: LogLevel = LogLevel.Info) {
		this.minLevel = minLevel;

		this.pino = pino({
			transport: config.isProd ? undefined : { target: "pino-pretty", options: { colorize: true } },
			base: {
				pid: false,
			},
			level: "trace",
			...options,
		});
	}

	public has(level: LogLevel): boolean {
		return level >= this.minLevel && level !== LogLevel.None;
	}

	public write(level: LogLevel, ...values: readonly unknown[]): void {
		if (!this.has(level)) return;

		const { name, msg, obj } = this.extractModuleAndPayload(values);
		const payload = { name, ...obj };

		switch (level) {
			case LogLevel.Trace:
				this.pino.trace(payload, msg);
				break;
			case LogLevel.Debug:
				this.pino.debug(payload, msg);
				break;
			case LogLevel.Info:
				this.pino.info(payload, msg);
				break;
			case LogLevel.Warn:
				this.pino.warn(payload, msg);
				break;
			case LogLevel.Error:
				this.pino.error(payload, msg);
				break;
			case LogLevel.Fatal:
				this.pino.fatal(payload, msg);
				break;
			default:
				break;
		}
	}

	public trace(...values: readonly unknown[]): void {
		this.write(LogLevel.Trace, ...values);
	}
	public debug(...values: readonly unknown[]): void {
		this.write(LogLevel.Debug, ...values);
	}
	public info(...values: readonly unknown[]): void {
		this.write(LogLevel.Info, ...values);
	}
	public warn(...values: readonly unknown[]): void {
		this.write(LogLevel.Warn, ...values);
	}
	public error(...values: readonly unknown[]): void {
		this.write(LogLevel.Error, ...values);
	}
	public fatal(...values: readonly unknown[]): void {
		this.write(LogLevel.Fatal, ...values);
	}

	private extractModuleAndPayload(values: readonly unknown[]): {
		name: string;
		msg: string;
		obj?: Record<string, unknown>;
	} {
		let name = "sapphire";
		let msg = "";
		let err: Error | undefined = undefined;
		const extra: unknown[] = [];
		const args = [...values];

		if (args.length > 0 && typeof args[0] === "string") {
			const firstArg = args[0];
			const colonIndex = firstArg.indexOf(":");

			if (colonIndex !== -1) {
				name = firstArg.substring(0, colonIndex).trim();
				const remainingMessage = firstArg.substring(colonIndex + 1).trim();

				if (remainingMessage) args[0] = remainingMessage;
				else args.shift();
			}
		}

		for (const val of args) {
			if (val instanceof Error) err = val;
			else if (typeof val === "object" && val !== null) extra.push(val);
			else msg += (msg ? " " : "") + String(val);
		}

		const obj: Record<string, any> = {};
		if (err) obj.err = err;
		if (extra.length > 0) obj.extra = extra;

		return { name, msg, obj };
	}
}