From da5f92939ac26815cd1913c86064e176693d2c12 Mon Sep 17 00:00:00 2001 From: Hirzi Date: Fri, 1 Nov 2024 12:39:27 +0700 Subject: [PATCH] feat: error logs file --- .gitignore | 8 ++-- README.md | 16 ++++---- guide/changing-env-configuration.md | 4 +- handlers/application.js | 2 +- handlers/errorLogging.js | 17 +++++++++ handlers/getStats.js | 4 +- handlers/getWingsStatus.js | 2 + handlers/sendMessage.js | 58 +++++++++++++++-------------- index.js | 11 ++++++ package.json | 9 +++-- 10 files changed, 84 insertions(+), 47 deletions(-) create mode 100644 handlers/errorLogging.js diff --git a/.gitignore b/.gitignore index 85f6cee..66c97b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ config-dev.yml package-lock.json -.vscode -node_modules +/.vscode +/node_modules cache.json .env -.setup-complete \ No newline at end of file +.setup-complete +logs.txt +/logs \ No newline at end of file diff --git a/README.md b/README.md index 42efb31..b078a7e 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,9 @@ PteroStats is a Discord App/Bot designed to check Pterodactyl or Pelican Panel stats and post it to your Discord server. ## Preview -
- PteroStats Setup Preview - PteroStats Image Preview - PteroStats Console Preview -
+PteroStats Setup Preview +PteroStats Image Preview +PteroStats Console Preview ## Guide - [Starting the App/Bot](#starting-the-appbot) @@ -37,15 +35,15 @@ PteroStats is a Discord App/Bot designed to check Pterodactyl or Pelican Panel s Setup - - [Getting an Panel API key](https://github.com/HirziDevs/PteroStats/blob/main/guide/panel-api-key.md) - - [Getting a Channel ID](https://github.com/HirziDevs/PteroStats/blob/main/guide/channel-id.md) + - [How to get Panel API key](https://github.com/HirziDevs/PteroStats/blob/main/guide/panel-api-key.md) + - [How to get Channel ID](https://github.com/HirziDevs/PteroStats/blob/main/guide/channel-id.md) 6. Run `node index.js` if you want to start the app/bot again, and you're done! Console Logging ## Reporting a Bug -Enable `log_error` in the `config.yml` file and check the console for the error message. After that, report it to our Discord server at [Support Server](https://discord.znproject.my.id). +Enable `log_error` in the `config.yml` file and check the console for the error message. Please also send the `logs.txt` file created by the bot, which contains information that will help with the bug report. After that, report it to our Discord server at [Support Server](https://discord.znproject.my.id). ## Links ### Support Server @@ -54,4 +52,4 @@ Enable `log_error` in the `config.yml` file and check the console for the error ### Pterodactyl & Pelican Panel server Please do not ask about PteroStats here. - [Pterodactyl Discord Server](https://discord.gg/pterodactyl) -- [Pelican Discord Server](https://discord.gg/pelican-panel) +- [Pelican Discord Server](https://discord.gg/pelican-panel) \ No newline at end of file diff --git a/guide/changing-env-configuration.md b/guide/changing-env-configuration.md index 9451f4b..2a2774f 100644 --- a/guide/changing-env-configuration.md +++ b/guide/changing-env-configuration.md @@ -7,8 +7,8 @@ Setup - - [Getting an Panel API key](https://github.com/HirziDevs/PteroStats/blob/main/guide/panel-api-key.md) - - [Getting a Channel ID](https://github.com/HirziDevs/PteroStats/blob/main/guide/channel-id.md) + - [How to get Panel API key](https://github.com/HirziDevs/PteroStats/blob/main/guide/panel-api-key.md) + - [How to get Channel ID](https://github.com/HirziDevs/PteroStats/blob/main/guide/channel-id.md) 3. Run `node index.js` if you want to start the app/bot again, and you're done! diff --git a/handlers/application.js b/handlers/application.js index c06d2da..4a24cff 100644 --- a/handlers/application.js +++ b/handlers/application.js @@ -52,7 +52,7 @@ module.exports = function Application() { try { client.login(process.env?.DiscordBotToken); } catch { - console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error | Invalid Discord Bot Token! Make sure you have the correct token in the config!")); + console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error | Invalid Discord Bot Token! Make sure you have the correct token in the config!")); process.exit(); } } \ No newline at end of file diff --git a/handlers/errorLogging.js b/handlers/errorLogging.js new file mode 100644 index 0000000..7b9b4af --- /dev/null +++ b/handlers/errorLogging.js @@ -0,0 +1,17 @@ +const fs = require("node:fs"); +const cliColor = require("cli-color"); +const yaml = require("js-yaml"); +const package = require("../package.json") + +module.exports = function ErrorLogging(error, isNotError) { + if (!isNotError) console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.yellowBright(`Something went wrong.`)) + + if (!fs.existsSync("logs.txt")) { + const config = yaml.load(fs.readFileSync("./config.yml", "utf8")); + config.notifier.webhook = "REDACTED" + + fs.appendFileSync("logs.txt", "PACKAGE:\n\n" + yaml.dump(package) + "\n\n\n") + fs.appendFileSync("logs.txt", "CONFIGURATION:\n\n" + yaml.dump(config) + "\n\n\nERROR LOGS:\n\n") + } + fs.appendFileSync("logs.txt", `${new Date().toISOString()} | ${!isNotError ? "ERROR" : "WINGS"} | ${error.stack}\n`) +} \ No newline at end of file diff --git a/handlers/getStats.js b/handlers/getStats.js index f15c534..6240bba 100644 --- a/handlers/getStats.js +++ b/handlers/getStats.js @@ -3,7 +3,8 @@ const getNodeConfiguration = require("./getNodeConfiguration.js"); const getNodesDetails = require("./getNodesDetails.js"); const getWingsStatus = require("./getWingsStatus.js"); const promiseTimeout = require("./promiseTimeout.js"); -const sendMessage = require("./sendMessage.js") +const errorLogging = require("./errorLogging.js"); +const sendMessage = require("./sendMessage.js"); const getServers = require("./getServers.js"); const config = require("./configuration.js"); const getUsers = require("./getUsers.js"); @@ -103,6 +104,7 @@ module.exports = async function getStats(client) { return sendMessage(data); } catch (error) { if (config.log_error) console.error(error) + errorLogging(error) console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Panel is currently offline.")); return fs.readFile(path.join(__dirname, "../cache.json"), (err, data) => { diff --git a/handlers/getWingsStatus.js b/handlers/getWingsStatus.js index 68d5c10..e9dd6f3 100644 --- a/handlers/getWingsStatus.js +++ b/handlers/getWingsStatus.js @@ -1,3 +1,4 @@ +const errorLogging = require("./errorLogging.js"); const config = require("./configuration.js"); module.exports = async function getWingsStatus(node, nodeToken) { @@ -12,6 +13,7 @@ module.exports = async function getWingsStatus(node, nodeToken) { .then(() => true) .catch((error) => { if (config.log_error) console.error(error); + errorLogging(error, true) return false }) } \ No newline at end of file diff --git a/handlers/sendMessage.js b/handlers/sendMessage.js index f4bcd69..9988c68 100644 --- a/handlers/sendMessage.js +++ b/handlers/sendMessage.js @@ -2,6 +2,7 @@ const { EmbedBuilder, time, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); const uptimeFormatter = require("./uptimeFormatter.js"); const convertUnits = require("./convertUnits.js"); +const errorLogging = require("./errorLogging.js"); const config = require("./configuration.js"); const cliColor = require("cli-color"); @@ -19,28 +20,28 @@ module.exports = async function sendMessage({ client, cache, panel, uptime, node let embeds = [embed]; - if (config.nodes_settings.details) { - nodes.forEach((node, index) => { - if (index % 25 === 0 && index !== 0) { - embed = new EmbedBuilder().setColor(config.embed.nodes.color); - if (embeds.length < 9) embeds.push(embed); - } - - embed.addFields({ - name: `${node.attributes.name} - ${node.status ? config.status.online : config.status.offline}`, - value: - "```\n" + - (config.nodes_settings.host ? `Host : ${node.attributes.fqdn}\n` : "") + - `Memory : ${convertUnits(node.attributes.allocated_resources.memory, node.attributes.memory, config.nodes_settings.unit)}\n` + - `Disk : ${convertUnits(node.attributes.allocated_resources.disk, node.attributes.disk, config.nodes_settings.unit)}` + - (node.attributes?.allocated_resources?.cpu ? `\nCPU : ${node.attributes?.allocated_resources?.cpu || 0}%` : "") + - (config.nodes_settings.servers ? `\nServers: ${node.attributes.relationships.servers}${config.nodes_settings.allocations_as_max_servers ? ` / ${node.attributes.relationships.allocations}` : ""}` : "") + - (config.nodes_settings.uptime ? `\nUptime : ${node.uptime ? uptimeFormatter(Date.now() - node.uptime) : "N/A"}` : "") + - "```" + if (nodes && nodes.length > 0) { + if (config.nodes_settings.details) { + nodes.forEach((node, index) => { + if (index % 25 === 0 && index !== 0) { + embed = new EmbedBuilder().setColor(config.embed.nodes.color); + if (embeds.length < 9) embeds.push(embed); + } + + embed.addFields({ + name: `${node.attributes.name} - ${node.status ? config.status.online : config.status.offline}`, + value: + "```\n" + + (config.nodes_settings.host ? `Host : ${node.attributes.fqdn}\n` : "") + + `Memory : ${convertUnits(node.attributes.allocated_resources.memory, node.attributes.memory, config.nodes_settings.unit)}\n` + + `Disk : ${convertUnits(node.attributes.allocated_resources.disk, node.attributes.disk, config.nodes_settings.unit)}` + + (node.attributes?.allocated_resources?.cpu ? `\nCPU : ${node.attributes?.allocated_resources?.cpu || 0}%` : "") + + (config.nodes_settings.servers ? `\nServers: ${node.attributes.relationships.servers}${config.nodes_settings.allocations_as_max_servers ? ` / ${node.attributes.relationships.allocations}` : ""}` : "") + + (config.nodes_settings.uptime ? `\nUptime : ${node.uptime ? uptimeFormatter(Date.now() - node.uptime) : "N/A"}` : "") + + "```" + }); }); - }); - } else { - embeds[0].setDescription((embed.data.description ? (embed.data.description + "\n\n") : "") + nodes.map(node => `**${node.attributes.name}** - ${node.status ? config.status.online : config.status.offline}`).join("\n")); + } else embeds[0].setDescription((embed.data.description ? (embed.data.description + "\n\n") : "") + nodes.map(node => `**${node.attributes.name}** - ${node.status ? config.status.online : config.status.offline}`).join("\n")); } let panelEmbed = new EmbedBuilder() @@ -87,7 +88,7 @@ module.exports = async function sendMessage({ client, cache, panel, uptime, node }) .setImage(config.embed.nodes.image || null) - if (!cache && !panel) { + if ((!cache && !panel) || (!nodes || nodes.length < 1)) { embeds[embeds.length - 1].setDescription( embeds[embeds.length - 1].data.description ? embeds[embeds.length - 1].data.description + "\n\nThere are no nodes to be display!" : "There are no nodes to be display!" ); @@ -131,20 +132,21 @@ module.exports = async function sendMessage({ client, cache, panel, uptime, node } catch (error) { try { if (error.rawError?.code === 429) { - console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Error 429 | Your IP has been rate limited by either Discord or your website. If it's a rate limit with Discord, you must wait. If it's a issue with your website, consider whitelisting your server IP.")); + console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Error 429 | Your IP has been rate limited by either Discord or your website. If it's a rate limit with Discord, you must wait. If it's a issue with your website, consider whitelisting your server IP.")); } else if (error.rawError?.code === 403) { - console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("FORBIDDEN | The channel ID you provided is incorrect. Please double check you have the right ID. If you're not sure, read our documentation: \n>>https://github.com/HirziDevs/PteroStats#getting-channel-id<<")); + console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("FORBIDDEN | The channel ID you provided is incorrect. Please double check you have the right ID. If you're not sure, read our documentation: \n>>https://github.com/HirziDevs/PteroStats#getting-channel-id<<")); } else if (error.code === "ENOTFOUND") { - console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("ENOTFOUND | DNS Error. Ensure your network connection and DNS server are functioning correctly.")); + console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("ENOTFOUND | DNS Error. Ensure your network connection and DNS server are functioning correctly.")); } else if (error.rawError?.code === 50001) { - console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error | Your discord bot doesn't have access to see/send message/edit message in the channel!")); + console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error | Your discord bot doesn't have access to see/send message/edit message in the channel!")); } else if (error.rawError?.errors && Object?.values(error.rawError.errors)[0]?._errors[0]?.code === "MAX_EMBED_SIZE_EXCEEDED") { - console.log(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error | Embed message limit exceeded! Please limit or decrease the nodes that need to be shown in the config!")); + console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error | Embed message limit exceeded! Please limit or decrease the nodes that need to be shown in the config!")); } else if (error.rawError?.errors && Object?.values(error.rawError.errors)[0]?._errors[0]?.code) { - console.log(Object.values(error.rawError.errors)[0]._errors[0].message); + console.error(Object.values(error.rawError.errors)[0]._errors[0].message); } else { console.error(cliColor.cyanBright("[PteroStats] ") + cliColor.redBright("Discord Error"), error); } + errorLogging(error) process.exit(); } catch (err) { console.error(error) diff --git a/index.js b/index.js index 7c07717..c55b81f 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,14 @@ const fs = require("node:fs"); const cliColor = require("cli-color"); const package = require("./package.json"); +const axios = require("axios"); +const errorLogging = require("./handlers/errorLogging.js"); + +process.stdout.write(cliColor.reset); +if (fs.existsSync("logs.txt")) { + if (!fs.existsSync("./logs")) fs.mkdirSync("./logs") + fs.renameSync("logs.txt", `logs/${Date.now()}.txt`); +} console.log( ` _${cliColor.blueBright.bold(`${cliColor.underline("Ptero")}dact${cliColor.underline("yl & P")}eli${cliColor.underline("can")}`)}___ ______ ______ \n` + @@ -20,4 +28,7 @@ console.log( if (!fs.existsSync(".env") || !fs.existsSync(".setup-complete")) return require("./handlers/setup.js")(); +process.on('uncaughtException', (error) => errorLogging(error)) +process.on('unhandledRejection', (error) => errorLogging(error)) + require("./handlers/application.js")(); \ No newline at end of file diff --git a/package.json b/package.json index 7bd56e4..a6d993c 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,13 @@ { "name": "pterostats", - "version": "4.0.0", + "version": "4.1.0", "description": "PteroStats is a Discord App/Bot designed to check Pterodactyl or Pelican Panel stats and post it to your Discord server.", "license": "MIT", - "repository": "HirziDevs/PteroStats", "homepage": "https://pterostats.znproject.my.id", + "repository": { + "type": "git", + "url": "git+https://github.com/HirziDevs/PteroStats.git" + }, "bugs": { "email": "hirzi@znproject.my.id", "url": "https://github.com/HirziDevs/PteroStats/issues" @@ -23,4 +26,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +}