From 36deb7cef48deb37cb92bd09b7f5e063b3acbb03 Mon Sep 17 00:00:00 2001 From: Manuel Date: Sun, 15 Oct 2023 18:47:11 +0200 Subject: [PATCH 1/5] feat: add logger --- .env.example | 1 + .eslintrc.yaml | 4 ++ src/core/loadModules.ts | 2 + src/core/loaderCommands.ts | 2 + src/core/logger.ts | 41 +++++++++++++++++++ src/core/routeHandlers.ts | 1 + src/main.ts | 2 +- .../recurringMessage.helpers.ts | 3 +- 8 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/core/logger.ts diff --git a/.env.example b/.env.example index 38edbc1e..86baffc7 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ # SETUP DISCORD_TOKEN= +LOGLEVEL= # DB REDIS_URL= diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 4dec9bf7..8243441b 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -21,6 +21,10 @@ settings: import/resolver: rules: + no-restricted-syntax: + - error + - selector: CallExpression[callee.object.name='console'][callee.property.name!=/^(log|warn|error|info|trace)$/] + message: Use logger instead of console import/exports-last: error import/first: error import/no-duplicates: error diff --git a/src/core/loadModules.ts b/src/core/loadModules.ts index 309680b9..39a6fd87 100644 --- a/src/core/loadModules.ts +++ b/src/core/loadModules.ts @@ -4,6 +4,7 @@ import { checkUniqueSlashCommandNames } from './checkUniqueSlashCommandNames'; import type { CreatedModule } from './createModule'; import { env } from './env'; import { pushCommands, routeCommands } from './loaderCommands'; +import { coreLogger } from './logger'; import { routeHandlers } from './routeHandlers'; export const loadModules = async ( @@ -15,6 +16,7 @@ export const loadModules = async ( const botCommands = modules.flatMap((module) => module.slashCommands ?? []); checkUniqueSlashCommandNames(botCommands); + coreLogger.info('Routing slashcommands to interactionCreate event.'); routeCommands(client, botCommands); const clientId = client.application?.id; diff --git a/src/core/loaderCommands.ts b/src/core/loaderCommands.ts index 56edd4d3..9eec622f 100644 --- a/src/core/loaderCommands.ts +++ b/src/core/loaderCommands.ts @@ -8,6 +8,7 @@ import { import type { BotCommand } from '../types/bot'; import { deleteExistingCommands } from './deleteExistingCommands'; +import { coreLogger } from './logger'; interface PushCommandsOptions { commands: RESTPostAPIChatInputApplicationCommandsJSONBody[]; @@ -62,6 +63,7 @@ export const pushCommands = async ({ await rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands, }); + coreLogger.info('All commands are pushed.'); }; export const routeCommands = (client: Client, botCommands: BotCommand[]) => diff --git a/src/core/logger.ts b/src/core/logger.ts new file mode 100644 index 00000000..eb3e44c5 --- /dev/null +++ b/src/core/logger.ts @@ -0,0 +1,41 @@ +import createLogger, { type LoggerOptions } from 'pino'; +import type pinodev from 'pino-dev'; +import type { PrettyOptions } from 'pino-pretty'; + +type PrettyDevOptions = Parameters[0]; +type BotLoggerOptions = LoggerOptions & + ( + | { transport?: { target: 'pino-dev'; options: PrettyDevOptions } } + | { transport?: { target: 'pino-pretty'; options: PrettyOptions } } + ); + +const developmentOptionsOverride: BotLoggerOptions = { + transport: { + target: 'pino-dev', + options: { + colorize: true, + // propertyMap: { + // module: '[module]', + // }, + }, + }, + // transport: { + // target: 'pino-pretty', + // options: { + // customPrettifiers: { + // // module: (name) => `[${name}]`, + // }, + // }, + // }, + level: process.env['LOGLEVEL'] ?? 'debug', +}; + +const defaultLogger = createLogger({ + level: process.env['LOGLEVEL'] ?? 'info', + ...(process.env['NODE_ENV'] === 'production' ? {} : developmentOptionsOverride), +}); + +export const createLoggerForModule = (moduleName: string) => + defaultLogger.child({ module: moduleName }); + +export const coreLogger = createLoggerForModule('core'); diff --git a/src/core/routeHandlers.ts b/src/core/routeHandlers.ts index 511b24c2..00c8b99d 100644 --- a/src/core/routeHandlers.ts +++ b/src/core/routeHandlers.ts @@ -2,6 +2,7 @@ import type { Client, ClientEvents } from 'discord.js'; import type { EventHandler } from '../types/bot'; import type { CreatedModule } from './createModule'; +import { coreLogger } from './logger'; const handleEvent = async ( eventHandlers: EventHandler[], diff --git a/src/main.ts b/src/main.ts index 38851607..837a1c88 100644 --- a/src/main.ts +++ b/src/main.ts @@ -41,4 +41,4 @@ if (!client.isReady()) { await loadModules(client, createdModules); -console.log('Bot started.'); +coreLogger.info('Bot fully started.'); diff --git a/src/modules/recurringMessage/recurringMessage.helpers.ts b/src/modules/recurringMessage/recurringMessage.helpers.ts index e5ced91e..978b92da 100644 --- a/src/modules/recurringMessage/recurringMessage.helpers.ts +++ b/src/modules/recurringMessage/recurringMessage.helpers.ts @@ -51,8 +51,7 @@ export const createRecurringMessage = ( () => { const channel = client.channels.cache.get(channelId); if (!channel || !channel.isTextBased()) { - console.error(`Channel ${channelId} not found`); - return; + throw new Error(`Channel ${channelId} not found`); } void channel.send(message); }, From 027728f94a8c26c6b7392a5361a9b7be965c32be Mon Sep 17 00:00:00 2001 From: Manuel Date: Sun, 15 Oct 2023 20:30:44 +0200 Subject: [PATCH 2/5] chore: remove pino-dev --- src/core/logger.ts | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/core/logger.ts b/src/core/logger.ts index eb3e44c5..b2d254bc 100644 --- a/src/core/logger.ts +++ b/src/core/logger.ts @@ -1,32 +1,17 @@ import createLogger, { type LoggerOptions } from 'pino'; -import type pinodev from 'pino-dev'; import type { PrettyOptions } from 'pino-pretty'; -type PrettyDevOptions = Parameters[0]; -type BotLoggerOptions = LoggerOptions & - ( - | { transport?: { target: 'pino-dev'; options: PrettyDevOptions } } - | { transport?: { target: 'pino-pretty'; options: PrettyOptions } } - ); +type BotLoggerOptions = LoggerOptions & { + transport?: { target: 'pino-pretty'; options: PrettyOptions }; +}; const developmentOptionsOverride: BotLoggerOptions = { transport: { - target: 'pino-dev', + target: 'pino-pretty', options: { colorize: true, - // propertyMap: { - // module: '[module]', - // }, }, }, - // transport: { - // target: 'pino-pretty', - // options: { - // customPrettifiers: { - // // module: (name) => `[${name}]`, - // }, - // }, - // }, level: process.env['LOGLEVEL'] ?? 'debug', }; From 7f8fd03f84c1f7775181a913d3bcfba5987b5776 Mon Sep 17 00:00:00 2001 From: Manuel Date: Sun, 15 Oct 2023 22:51:49 +0200 Subject: [PATCH 3/5] chore: create transport module for formatting in dev --- src/core/logger.ts | 12 ++---------- src/core/pinoTransportModule.ts | 11 +++++++++++ tsup.config.ts | 5 +++++ 3 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 src/core/pinoTransportModule.ts diff --git a/src/core/logger.ts b/src/core/logger.ts index b2d254bc..bf343f0d 100644 --- a/src/core/logger.ts +++ b/src/core/logger.ts @@ -1,16 +1,8 @@ import createLogger, { type LoggerOptions } from 'pino'; -import type { PrettyOptions } from 'pino-pretty'; -type BotLoggerOptions = LoggerOptions & { - transport?: { target: 'pino-pretty'; options: PrettyOptions }; -}; - -const developmentOptionsOverride: BotLoggerOptions = { +const developmentOptionsOverride: LoggerOptions = { transport: { - target: 'pino-pretty', - options: { - colorize: true, - }, + target: './pinoTransportModule', }, level: process.env['LOGLEVEL'] ?? 'debug', }; diff --git a/src/core/pinoTransportModule.ts b/src/core/pinoTransportModule.ts new file mode 100644 index 00000000..6e86809e --- /dev/null +++ b/src/core/pinoTransportModule.ts @@ -0,0 +1,11 @@ +import { red, white } from 'colorette'; +import pretty from 'pino-pretty'; + +export default (opts: Parameters) => + pretty({ + ...opts, + colorize: true, + messageFormat: white(`[${red('{module}')}] {msg}`), + hideObject: true, + ignore: 'pid,hostname', + }); diff --git a/tsup.config.ts b/tsup.config.ts index d6ad64d4..770cf9d3 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,7 +1,12 @@ +//eslint-disable-next-line import/no-extraneous-dependencies import { defineConfig } from 'tsup'; export default defineConfig({ clean: true, + entry: { + main: 'src/main.ts', + pinoTransportModule: 'src/core/pinoTransportModule.ts', + }, format: ['esm'], keepNames: true, minify: true, From bbe02828147abff846f2d2e882753286cc10f2a9 Mon Sep 17 00:00:00 2001 From: Manuel Date: Sun, 15 Oct 2023 23:26:43 +0200 Subject: [PATCH 4/5] chore: inject child logger in modules --- src/core/createModule.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/createModule.ts b/src/core/createModule.ts index 048bab2d..4882887a 100644 --- a/src/core/createModule.ts +++ b/src/core/createModule.ts @@ -1,5 +1,6 @@ import { constantCase } from 'change-case'; import type { ClientEvents, ClientOptions } from 'discord.js'; +import type { Logger } from 'pino'; import type { ZodTypeAny } from 'zod'; import { z } from 'zod'; @@ -11,6 +12,7 @@ type InferredZodShape> = { interface Context> { env: InferredZodShape; + logger: Logger; } type ModuleFunction, ReturnType> = ( @@ -31,6 +33,7 @@ type BotModule> = { interface CreatedModuleInput { env: unknown; + logger: Logger; } type ModuleFactory = (input: CreatedModuleInput) => Promise; From 6a1633209fb628482812ac147b33d9c377115baf Mon Sep 17 00:00:00 2001 From: Manuel Date: Mon, 16 Oct 2023 00:14:17 +0200 Subject: [PATCH 5/5] chore: add logs --- .../voiceOnDemand/voiceOnDemand.module.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/modules/voiceOnDemand/voiceOnDemand.module.ts b/src/modules/voiceOnDemand/voiceOnDemand.module.ts index e661f3c8..3e588f11 100644 --- a/src/modules/voiceOnDemand/voiceOnDemand.module.ts +++ b/src/modules/voiceOnDemand/voiceOnDemand.module.ts @@ -52,6 +52,7 @@ export const voiceOnDemand = createModule({ //NOTES: this is a potential race condition. await cache.set('lobbyIds', [...lobbyIds, id]); + logger.info(`Created voice on demand voice channel ${id}`); await interaction.reply({ content: 'Created voice on demand voice channel.', ephemeral: true, @@ -60,7 +61,7 @@ export const voiceOnDemand = createModule({ }, }, ], - eventHandlers: () => ({ + eventHandlers: ({ logger }) => ({ voiceStateUpdate: async (oldState, newState) => { const lobbyIds = await cache.get('lobbyIds', []); const onDemandChannels = await cache.get('onDemandChannels', []); @@ -73,10 +74,18 @@ export const voiceOnDemand = createModule({ } if (isOnDemandChannel && isLeaveState(oldState)) { + logger.debug( + { guild: newState.guild.id }, + `User ${oldState.member.displayName} left the on-demand channel`, + ); await handleLeaveOnDemand(oldState); } if (isLobbyChannel && isJoinState(newState)) { + logger.debug( + { guild: newState.guild.id }, + `User ${newState.member.displayName} joined the lobby`, + ); await handleJoinLobby(newState); } }, @@ -92,6 +101,11 @@ export const voiceOnDemand = createModule({ return; } + logger.info( + { guild: channel.guild.id }, + `Voice on demand voice channel ${channel.id} was deleted`, + ); + await cache.set( 'lobbyIds', lobbyIds.filter((lobbyId) => lobbyId !== channel.id),