102 lines
4.1 KiB
JavaScript
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,
|
|
};
|