Files
JogyoGaori/utils/errorHandler.js
2025-08-07 01:18:49 +09:00

102 lines
4.1 KiB
JavaScript

const { EmbedBuilder } = require('discord.js');
require('dotenv').config();
const logger = require('../../modules/colorfulLogger');
const logErrorToConsole = (error, context) => {
console.error(`\n\x1b[31m[${new Date().toISOString()}] \x1b[33m[${context || 'ERROR'}]\x1b[0m`);
console.error(error);
};
const sendErrorToDiscord = async (error, client, contextInfo) => {
try {
const errorLogChannelId = process.env.ERROR_LOG_CHANNEL_ID;
if (!errorLogChannelId || !client?.channels) return;
const errorEmbed = new EmbedBuilder()
.setColor(0xFF0000)
.setTitle('오류 발생')
.setTimestamp();
if (typeof contextInfo === 'string') {
errorEmbed.addFields({ name: '오류 발생 위치', value: contextInfo });
} else if (contextInfo?.isInteraction) {
const interaction = contextInfo;
errorEmbed.setTitle('명령어 인터랙션 오류');
errorEmbed.addFields(
{ name: '명령어', value: `\`/${interaction.commandName}\``, inline: true },
{ name: '사용자', value: `${interaction.user.tag} (\`${interaction.user.id}\`)`, inline: true },
{ name: '서버/채널', value: `${interaction.guild.name} / #${interaction.channel.name}`, inline: false }
);
} else if (contextInfo?.author) {
const message = contextInfo;
errorEmbed.setTitle('메시지 처리 오류');
errorEmbed.addFields(
{ name: '메시지 내용', value: message.content.substring(0, 200) },
{ name: '사용자', value: `${message.author.tag} (\`${message.author.id}\`)`, inline: true },
{ name: '서버/채널', value: `${message.guild.name} / #${message.channel.name}`, inline: true }
);
}
errorEmbed.addFields(
{ name: '오류 메시지', value: `\`\`\`${error.message}\`\`\`` },
{ name: 'Stack Trace', value: `\`\`\`javascript\n${error.stack.substring(0, 1000)}\`\`\`` }
);
const channel = await client.channels.fetch(errorLogChannelId).catch(() => null);
if (channel?.isTextBased()) {
await channel.send({ embeds: [errorEmbed] });
}
} catch (discordError) {
console.error('\n\x1b[1m\x1b[31m[FATAL] Discord로 오류 로그 전송에 실패했습니다.\x1b[0m');
logErrorToConsole(discordError, 'DISCORD LOG SEND FAILED');
logErrorToConsole(error, 'ORIGINAL ERROR');
}
};
const handleCommandError = async (error, context, client) => {
logErrorToConsole(error, context?.commandName || context?.content || 'Command Execution');
await sendErrorToDiscord(error, client, context);
if (context?.isInteraction) {
const interaction = context;
const reply = {
content: '명령어를 실행하는 중 오류가 발생했습니다.',
embeds: [],
ephemeral: true,
};
try {
if (interaction.replied || interaction.deferred) {
await interaction.followUp(reply);
} else {
await interaction.reply(reply);
}
} catch (replyError) {
logErrorToConsole(replyError, 'COMMAND ERROR REPLY FAILED');
}
} else if (context?.channel) {
try {
await context.channel.send({ content: '명령어를 처리하는 중 오류가 발생했습니다.' });
} catch (replyError) {
logErrorToConsole(replyError, 'COMMAND ERROR REPLY FAILED');
}
}
};
const handleFatalError = async (error, context, client, shutdownLogic) => {
logErrorToConsole(error, context);
await sendErrorToDiscord(error, client, context);
if (typeof shutdownLogic === 'function') {
logger.error('Fatal error detected. Performing shutdown logic before exit...');
await shutdownLogic();
}
logger.error('치명적인 오류로 인해 프로세스를 종료합니다.');
process.exit(1);
};
module.exports = {
handleCommandError,
handleFatalError,
};