171 lines
5.5 KiB
JavaScript
171 lines
5.5 KiB
JavaScript
/**
|
||
* Structured logging service – posts embeds to dedicated Discord channels.
|
||
* Call setClient(client) from the main bot on ready so logs can be posted.
|
||
*/
|
||
const { EmbedBuilder } = require('discord.js');
|
||
const { CONFIG } = require('../config');
|
||
|
||
let client = null;
|
||
|
||
function setClient(c) {
|
||
client = c;
|
||
}
|
||
|
||
// --- Helpers ---
|
||
|
||
async function sendToChannel(channelId, embed, overrideClient) {
|
||
const c = overrideClient || client;
|
||
if (!c || !channelId) return;
|
||
try {
|
||
const channel = await c.channels.fetch(channelId);
|
||
if (channel) await channel.send({ embeds: [embed] });
|
||
} catch (_) {
|
||
// ignore send failures
|
||
}
|
||
}
|
||
|
||
// --- logError (backwards-compatible) ---
|
||
|
||
async function logError(context, error, interaction = null, overrideClient = null) {
|
||
const c = overrideClient || client;
|
||
if (!c || !CONFIG.DEBUGGING_CHANNEL_ID) return;
|
||
|
||
try {
|
||
const channel = await c.channels.fetch(CONFIG.DEBUGGING_CHANNEL_ID);
|
||
const userLine = interaction?.user?.tag
|
||
? `User: ${interaction.user.tag}\n`
|
||
: '';
|
||
const commandLine = (interaction?.commandName || interaction?.customId)
|
||
? `Command/Button: ${interaction.commandName || interaction.customId}\n`
|
||
: '';
|
||
const stack = (error.stack || error.message || String(error)).slice(0, 1500);
|
||
await channel.send({
|
||
content: `\`[${context}]\` ${error.message || String(error)}\n${userLine}${commandLine}\n\`\`\`${stack}\`\`\``
|
||
});
|
||
} catch (_) {
|
||
// ignore send failures
|
||
}
|
||
}
|
||
|
||
// --- logWarn ---
|
||
|
||
async function logWarn(context, message, overrideClient = null) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle(`Warning: ${context}`)
|
||
.setDescription(String(message).slice(0, 4000))
|
||
.setColor(0xFFFF00)
|
||
.setTimestamp();
|
||
await sendToChannel(CONFIG.DEBUGGING_CHANNEL_ID, embed, overrideClient);
|
||
}
|
||
|
||
// --- logEvent (generic – posts to any configured channel) ---
|
||
|
||
async function logEvent(channelConfigKey, embed, overrideClient = null) {
|
||
const channelId = CONFIG[channelConfigKey];
|
||
await sendToChannel(channelId, embed, overrideClient);
|
||
}
|
||
|
||
// --- logTicketEvent ---
|
||
|
||
async function logTicketEvent(action, fields, interaction = null) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle(action)
|
||
.setColor(CONFIG.EMBED_COLOR_INFO || 0x1e2124)
|
||
.addFields(fields.map(f => ({ name: f.name, value: String(f.value).slice(0, 1024), inline: f.inline ?? true })))
|
||
.setTimestamp();
|
||
if (interaction?.user?.tag) {
|
||
embed.setFooter({ text: interaction.user.tag });
|
||
}
|
||
await sendToChannel(CONFIG.LOG_CHAN, embed, interaction?.client);
|
||
}
|
||
|
||
// --- logGmail ---
|
||
|
||
async function logGmail(subject, sender, ticketNumber, game) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle('Email Ticket Created')
|
||
.setColor(0x00BFFF)
|
||
.addFields(
|
||
{ name: 'Subject', value: String(subject || 'No subject').slice(0, 256), inline: false },
|
||
{ name: 'Sender', value: String(sender || 'unknown'), inline: true },
|
||
{ name: 'Ticket #', value: String(ticketNumber || '?'), inline: true },
|
||
{ name: 'Game', value: String(game || 'Not detected'), inline: true }
|
||
)
|
||
.setTimestamp();
|
||
await sendToChannel(CONFIG.GMAIL_LOG_CHANNEL_ID, embed);
|
||
}
|
||
|
||
// --- logAutomation ---
|
||
|
||
async function logAutomation(action, ticketChannelName, detail) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle(action)
|
||
.setColor(0x9B59B6)
|
||
.setTimestamp();
|
||
if (ticketChannelName) {
|
||
embed.addFields({ name: 'Ticket', value: String(ticketChannelName), inline: true });
|
||
}
|
||
if (detail) {
|
||
embed.addFields({ name: 'Detail', value: String(detail).slice(0, 1024), inline: false });
|
||
}
|
||
await sendToChannel(CONFIG.AUTOMATION_LOG_CHANNEL_ID, embed);
|
||
}
|
||
|
||
// --- logSecurity ---
|
||
|
||
async function logSecurity(action, user, detail, overrideClient = null, color = 0xFF6600) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle('Security Event')
|
||
.setColor(color)
|
||
.addFields(
|
||
{ name: 'Action', value: String(action).slice(0, 256), inline: false },
|
||
{ name: 'User', value: user ? `${user.tag} (${user.id})` : 'Unknown', inline: true },
|
||
{ name: 'Detail', value: String(detail || 'N/A').slice(0, 1024), inline: false },
|
||
{ name: 'Timestamp', value: new Date().toISOString(), inline: true }
|
||
)
|
||
.setTimestamp();
|
||
await sendToChannel(CONFIG.SECURITY_LOG_CHANNEL_ID, embed, overrideClient);
|
||
}
|
||
|
||
// --- logIntegrity ---
|
||
|
||
async function logIntegrity(issue, detail, overrideClient = null) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle('Ticket Integrity Issue')
|
||
.setColor(0xFF0000)
|
||
.addFields(
|
||
{ name: 'Issue', value: String(issue).slice(0, 256), inline: false },
|
||
{ name: 'Detail', value: String(detail || 'N/A').slice(0, 1024), inline: false },
|
||
{ name: 'Timestamp', value: new Date().toISOString(), inline: true }
|
||
)
|
||
.setTimestamp();
|
||
await sendToChannel(CONFIG.DEBUGGING_CHANNEL_ID, embed, overrideClient);
|
||
}
|
||
|
||
// --- logSystem ---
|
||
|
||
async function logSystem(message, fields = [], overrideClient = null, color = 0x0099ff) {
|
||
const embed = new EmbedBuilder()
|
||
.setTitle(message)
|
||
.setColor(color)
|
||
.setTimestamp();
|
||
if (fields.length > 0) {
|
||
embed.addFields(fields.map(f => ({ name: f.name, value: String(f.value).slice(0, 1024), inline: f.inline ?? true })));
|
||
}
|
||
embed.addFields({ name: 'Timestamp', value: new Date().toISOString(), inline: true });
|
||
await sendToChannel(CONFIG.SYSTEM_LOG_CHANNEL_ID, embed, overrideClient);
|
||
}
|
||
|
||
module.exports = {
|
||
setClient,
|
||
logError,
|
||
logWarn,
|
||
logEvent,
|
||
logTicketEvent,
|
||
logGmail,
|
||
logAutomation,
|
||
logSecurity,
|
||
logIntegrity,
|
||
logSystem
|
||
};
|