From 3b0bb0da22533bb3d087cf87897ff4263e3ff7de Mon Sep 17 00:00:00 2001 From: IRONM00N <64110067+IRONM00N@users.noreply.github.com> Date: Sun, 3 Apr 2022 12:30:23 -0400 Subject: feat(logging): use proxies for console.log etc instead of manipulating stdout and stderr directly --- src/bot.ts | 15 ++++-- src/lib/common/AutoMod.ts | 6 +-- src/lib/utils/BushLogger.ts | 114 ++++++++++++++++++++++-------------------- src/listeners/client/ready.ts | 2 +- 4 files changed, 73 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/bot.ts b/src/bot.ts index d18cd0d..752075b 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,8 +1,13 @@ -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; -import config from './config/options.js'; -import { Sentry } from './lib/common/Sentry.js'; -import { BushClient } from './lib/index.js'; +import { init } from './lib/utils/BushLogger.js'; +// creates proxies on console.log and console.warn +// also starts a REPL session +init(); + +const { dirname } = await import('path'); +const { fileURLToPath } = await import('url'); +const { default: config } = await import('./config/options.js'); +const { Sentry } = await import('./lib/common/Sentry.js'); +const { BushClient } = await import('./lib/index.js'); const isDry = process.argv.includes('dry'); if (!isDry) new Sentry(dirname(fileURLToPath(import.meta.url)) || process.cwd()); diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts index 1aa6266..db3e709 100644 --- a/src/lib/common/AutoMod.ts +++ b/src/lib/common/AutoMod.ts @@ -200,7 +200,7 @@ export class AutoMod { } }, (err: any, response: any) => { - if (err) return client.console.stdout(err?.message); + if (err) return console.log(err?.message); const normalize = (val: number, min: number, max: number) => (val - min) / (max - min); @@ -214,10 +214,10 @@ export class AutoMod { } }; - client.console.stdout(chalk.cyan(this.message.content)); + console.log(chalk.cyan(this.message.content)); Object.entries(response.data.attributeScores) .sort(([a], [b]) => a.localeCompare(b)) - .forEach(([key, value]: any[]) => client.console.raw(chalk.white(key), color(value.summaryScore.value))); + .forEach(([key, value]: any[]) => console.log(chalk.white(key), color(value.summaryScore.value))); } ); } diff --git a/src/lib/utils/BushLogger.ts b/src/lib/utils/BushLogger.ts index 30eba07..5effb52 100644 --- a/src/lib/utils/BushLogger.ts +++ b/src/lib/utils/BushLogger.ts @@ -1,63 +1,67 @@ import chalk from 'chalk'; // eslint-disable-next-line @typescript-eslint/no-unused-vars import { Embed, Util, type Message, type PartialTextBasedChannelFields } from 'discord.js'; -import repl, { REPL_MODE_STRICT } from 'repl'; +import repl, { REPLServer, REPL_MODE_STRICT } from 'repl'; +import { WriteStream } from 'tty'; import { inspect } from 'util'; import { type BushSendMessageType } from '../extensions/discord-akairo/BushClient.js'; -const REPL = repl.start({ - useColors: true, - terminal: true, - useGlobal: true, - replMode: REPL_MODE_STRICT, - breakEvalOnSigint: true -}); - +let REPL: REPLServer; let replGone = false; -REPL.on('exit', () => { - replGone = true; - process.exit(0); -}); +export function init() { + const kFormatForStdout = Object.getOwnPropertySymbols(console).find((sym) => sym.toString() === 'Symbol(kFormatForStdout)')!; + const kFormatForStderr = Object.getOwnPropertySymbols(console).find((sym) => sym.toString() === 'Symbol(kFormatForStderr)')!; -/** - * Custom logging utility for the bot. - */ -export class BushLogger { - public static stdout(string: string): void { - return this.#baseLog('stdout', string); - } + REPL = repl.start({ + useColors: true, + terminal: true, + useGlobal: true, + replMode: REPL_MODE_STRICT, + breakEvalOnSigint: true, + ignoreUndefined: true + }); - public static stderr(string: string): void { - return this.#baseLog('stderr', string); - } + const apply = (stream: WriteStream, symbol: symbol): ProxyHandler['apply'] => + function apply(target, thisArg, args) { + if (stream.isTTY) { + stream.moveCursor(0, -1); + stream.write('\n'); + stream.clearLine(0); + } - static #baseLog(type: 'log', ...content: any): void; - static #baseLog(type: 'stdout' | 'stderr' | 'log', content: string): void; - static #baseLog(type: 'stdout' | 'stderr' | 'log', content: string): void { - const stream: NodeJS.WriteStream = type === 'stdout' || type === 'log' ? process.stdout : process.stderr; + const ret = target(...args); - if (stream.isTTY) { - stream.moveCursor(0, -1); - stream.write('\n'); - stream.clearLine(0); - // eslint-disable-next-line prefer-rest-params - if (type === 'log') console.log(...[...arguments].slice(1)); - else stream.write(`${content}\n`); - stream.moveCursor(0, typeof content === 'string' ? content.split('\n').length : 1); - if (!replGone) REPL.displayPrompt(true); - } else { - // eslint-disable-next-line prefer-rest-params - if (type === 'log' || type === 'stdout') console.log(...[...arguments].slice(1)); - // eslint-disable-next-line prefer-rest-params - else console.error(...[...arguments].slice(1)); - } - } + if (stream.isTTY) { + const formatted = (console as any)[symbol](args) as string; - public static raw(...content: any[]) { - return this.#baseLog('log', ...content); - } + stream.moveCursor(0, formatted.split('\n').length); + if (!replGone) { + REPL.displayPrompt(true); + } + } + + return ret; + }; + + global.console.log = new Proxy(console.log, { + apply: apply(process.stdout, kFormatForStdout) + }); + + global.console.warn = new Proxy(console.warn, { + apply: apply(process.stderr, kFormatForStderr) + }); + + REPL.on('exit', () => { + replGone = true; + process.exit(0); + }); +} +/** + * Custom logging utility for the bot. + */ +export class BushLogger { /** * Parses the content surrounding by `<<>>` and emphasizes it with the given color or by making it bold. * @param content The content to parse. @@ -176,7 +180,7 @@ export class BushLogger { public static debug(content: any, depth = 0): void { if (!client.config.isDevelopment) return; const newContent = this.#inspectContent(content, depth, true); - this.stdout(`${chalk.bgMagenta(this.#getTimeStamp())} ${chalk.magenta('[Debug]')} ${newContent}`); + console.log(`${chalk.bgMagenta(this.#getTimeStamp())} ${chalk.magenta('[Debug]')} ${newContent}`); } /** @@ -185,7 +189,7 @@ export class BushLogger { */ public static debugRaw(...content: any): void { if (!client.config.isDevelopment) return; - this.#baseLog('log', `${chalk.bgMagenta(this.#getTimeStamp())} ${chalk.magenta('[Debug]')}`, ...content); + console.log(`${chalk.bgMagenta(this.#getTimeStamp())} ${chalk.magenta('[Debug]')}`, ...content); } /** @@ -198,7 +202,7 @@ export class BushLogger { public static async verbose(header: string, content: any, sendChannel = false, depth = 0): Promise { if (!client.config.logging.verbose) return; const newContent = this.#inspectContent(content, depth, true); - this.stdout( + console.log( `${chalk.bgGrey(this.#getTimeStamp())} ${chalk.grey(`[${header}]`)} ${this.#parseFormatting(newContent, 'blackBright')}` ); if (!sendChannel) return; @@ -218,7 +222,7 @@ export class BushLogger { public static async superVerbose(header: string, content: any, depth = 0): Promise { if (!client.config.logging.verbose) return; const newContent = this.#inspectContent(content, depth, true); - this.stdout( + console.log( `${chalk.bgHex('#949494')(this.#getTimeStamp())} ${chalk.hex('#949494')(`[${header}]`)} ${chalk.hex('#b3b3b3')(newContent)}` ); } @@ -230,7 +234,7 @@ export class BushLogger { */ public static async superVerboseRaw(header: string, ...content: any[]): Promise { if (!client.config.logging.verbose) return; - this.raw(`${chalk.bgHex('#a3a3a3')(this.#getTimeStamp())} ${chalk.hex('#a3a3a3')(`[${header}]`)}`, ...content); + console.log(`${chalk.bgHex('#a3a3a3')(this.#getTimeStamp())} ${chalk.hex('#a3a3a3')(`[${header}]`)}`, ...content); } /** @@ -243,7 +247,7 @@ export class BushLogger { public static async info(header: string, content: any, sendChannel = true, depth = 0): Promise { if (!client.config.logging.info) return; const newContent = this.#inspectContent(content, depth, true); - this.stdout( + console.log( `${chalk.bgCyan(this.#getTimeStamp())} ${chalk.cyan(`[${header}]`)} ${this.#parseFormatting(newContent, 'blueBright')}` ); if (!sendChannel) return; @@ -263,7 +267,7 @@ export class BushLogger { */ public static async warn(header: string, content: any, sendChannel = true, depth = 0): Promise { const newContent = this.#inspectContent(content, depth, true); - this.stderr( + console.warn( `${chalk.bgYellow(this.#getTimeStamp())} ${chalk.yellow(`[${header}]`)} ${this.#parseFormatting( newContent, 'yellowBright' @@ -287,7 +291,7 @@ export class BushLogger { */ public static async error(header: string, content: any, sendChannel = true, depth = 0): Promise { const newContent = this.#inspectContent(content, depth, true); - this.stderr( + console.warn( `${chalk.bgRedBright(this.#getTimeStamp())} ${chalk.redBright(`[${header}]`)} ${this.#parseFormatting( newContent, 'redBright' @@ -311,7 +315,7 @@ export class BushLogger { */ public static async success(header: string, content: any, sendChannel = true, depth = 0): Promise { const newContent = this.#inspectContent(content, depth, true); - this.stdout( + console.log( `${chalk.bgGreen(this.#getTimeStamp())} ${chalk.greenBright(`[${header}]`)} ${this.#parseFormatting( newContent, 'greenBright' diff --git a/src/listeners/client/ready.ts b/src/listeners/client/ready.ts index d53ed9b..c550c6b 100644 --- a/src/listeners/client/ready.ts +++ b/src/listeners/client/ready.ts @@ -19,7 +19,7 @@ export default class ReadyListener extends BushListener { userCount = `<<${client.users.cache.size.toLocaleString()}>>`; void client.logger.success('ready', `Logged in to ${tag} serving ${guildCount} guilds and ${userCount} users.`); - client.console.stdout( + console.log( chalk.blue( `------------------------------------------------------------------------------${ client.config.isDevelopment ? '---' : client.config.isBeta ? '----' : '' -- cgit