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 -
-
-
-
+
+
## 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
- - [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!
## 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 @@
- - [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);
- }
+ 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"}` : "") +
- "```"
+ 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
+}