diff --git a/.gitignore b/.gitignore index f563bb1..8cd2ca9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env node_modules -build \ No newline at end of file +build +logs \ No newline at end of file diff --git a/package.json b/package.json index 4df0cc5..ff97a17 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "axios": "^0.21.1", "discord.js": "^12.5.1", "dotenv": "^8.2.0", - "mongoose": "^5.11.6" + "mongoose": "^5.11.6", + "winston": "^3.3.3" }, "devDependencies": { "rimraf": "^3.0.2", diff --git a/src/commands/admin.ts b/src/commands/admin.ts index 9a1eff1..aa35efd 100644 --- a/src/commands/admin.ts +++ b/src/commands/admin.ts @@ -9,6 +9,7 @@ import adminfindsuggestor from "../handlers/admin/adminfindsuggestor"; import adminsay from "../handlers/admin/adminsay"; import Roles from "../data/calm/roles.json"; +import Logger from "../utils/logger/Logger"; module.exports = { name: "admin", aliases: ["administrator"], @@ -46,6 +47,8 @@ module.exports = { return; } + Logger.verbose(`Admin command ran by ${message.author.id}. ${message.content}`); + args[0] = args[0].toLowerCase(); if (args[0] === "manualchallenge") { adminmanualchallenge.run(client, message, args); diff --git a/src/commands/annonsuggestion.ts b/src/commands/annonsuggestion.ts index 960f89e..a4dcb70 100644 --- a/src/commands/annonsuggestion.ts +++ b/src/commands/annonsuggestion.ts @@ -29,7 +29,7 @@ module.exports = { secondReaction = "❎"; } - if (suggestionChannel === undefined) { + if (!suggestionChannel) { message.channel.send("Uh oh! We could not find a channel to put the suggestion in!"); return; } diff --git a/src/commands/help.ts b/src/commands/help.ts index bbe0bfc..65bf7c8 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,5 +1,6 @@ import { Message, MessageEmbed } from "discord.js"; import Client from "../structures/Client"; +import logger from "../utils/logger/Logger"; module.exports = { name: "help", @@ -72,7 +73,7 @@ module.exports = { } } catch (err) { message.channel.send("Sorry, we have encountered an error :sob:"); - console.log(err); + logger.error(err); } }, }; diff --git a/src/commands/lockdown.ts b/src/commands/lockdown.ts index fdd075c..3df61f5 100644 --- a/src/commands/lockdown.ts +++ b/src/commands/lockdown.ts @@ -2,6 +2,7 @@ import { Message, Role, TextChannel } from "discord.js"; import Client from "../structures/Client"; import channels from "../data/calm/channels.json"; import roles from "../data/calm/roles.json"; +import logger from "../utils/logger/Logger"; module.exports = { name: "lockdown", @@ -32,14 +33,12 @@ module.exports = { newsChannel = message.guild.channels.cache.find((chan) => chan.name === channels.IMPORTANT.NEWS.name) as TextChannel; } - if(guildMemberRole === undefined || nitroBoosterRole === undefined) { - return message.channel.send("Unable to find one or more roles. Please make sure the Guild Member role exists and the Nitro Booster role exists") + if (guildMemberRole === undefined || nitroBoosterRole === undefined) { + return message.channel.send("Unable to find one or more roles. Please make sure the Guild Member role exists and the Nitro Booster role exists"); } if (newsChannel) { - await newsChannel.send( - `**Attention,** \n<@${message.author.id}> has **initiated** a _server lockdown_. \nYou are **not muted**, but will not be able to talk until a server admin does \`c!unlock\`` - ); + await newsChannel.send(`**Attention,** \n<@${message.author.id}> has **initiated** a _server lockdown_. \nYou are **not muted**, but will not be able to talk until a server admin does \`c!unlock\``); } for (const categoryName in channels) { @@ -54,7 +53,7 @@ module.exports = { } if (!channel) { - console.log(`Channel ${channelProperties.name} wasn't found`); + logger.verbose(`Channel ${channelProperties.name} wasn't found`); } else if (channelProperties.membersOnly && fullLock) { channel.updateOverwrite(guildMemberRole, { SEND_MESSAGES: false, ADD_REACTIONS: false }); } else if (channelProperties.public && fullLock) { diff --git a/src/commands/staff.ts b/src/commands/staff.ts index 759c7b1..8c6e2ea 100644 --- a/src/commands/staff.ts +++ b/src/commands/staff.ts @@ -1,7 +1,8 @@ import { GuildEmoji, Message, MessageEmbed } from "discord.js"; import Client from "../structures/Client"; import HypixelApi from "../utils/api/HypixelApi"; -import { IPlayer } from "../utils/api/Interfaces" +import { IPlayer } from "../utils/api/Interfaces"; +import logger from "../utils/logger/Logger"; module.exports = { name: "staff", @@ -9,49 +10,55 @@ module.exports = { category: "Utility", usage: "staff", run: async function run(client: Client, message: Message) { - const guildStaff = await HypixelApi.getGuildStaff(); - if (!guildStaff) { - return message.channel.send("Error: To prevent ratelimiting this command is on cooldown. Please wait a little bit and then try again."); - } + HypixelApi.getGuildStaff() + .then(async (guildStaff) => { + let onlineEmote: GuildEmoji | string, offlineEmote: GuildEmoji | string; + if (message.guild.id === "501501905508237312") { + onlineEmote = client.emojis.cache.find((e) => e.id === "805656441704546324"); + offlineEmote = client.emojis.cache.find((e) => e.id === "805656538127401000"); + } else { + onlineEmote = "🟢"; + offlineEmote = "🔴"; + } - let onlineEmote: GuildEmoji | string, offlineEmote: GuildEmoji | string; - if(message.guild.id === "501501905508237312") { - onlineEmote = client.emojis.cache.find(e => e.id === "805656441704546324") - offlineEmote = client.emojis.cache.find(e => e.id === "805656538127401000"); - } else { - onlineEmote = "🟢"; - offlineEmote = "🔴"; - } + const tmp = await message.channel.send("Please wait while we fetch data from the api. This could take some time."); - const tmp = await message.channel.send("Please wait while we fetch data from the api. This could take some time."); - - let online = Array(); - let offline = Array(); + let online = Array(); + let offline = Array(); - for (const member in guildStaff) { - const player = await HypixelApi.getPlayerFromUUID(guildStaff[member].uuid); - - if (player.lastLogin > player.lastLogout) { - online.push(player); - } else { - offline.push(player); - } - } + for (const member in guildStaff) { + let player: IPlayer; + try { + player = await HypixelApi.getPlayerFromUUID(guildStaff[member].uuid); + } catch (err) { + logger.error(err); + return message.channel.send("An error happened while trying to perform this command! Please contact a developer."); + } - let embedDesc = ""; - online.forEach((player) => { - embedDesc += "`" + player.displayname + "` " + onlineEmote + "\n"; - }) - offline.forEach((player) => { - embedDesc += "`" + player.displayname + "` " + offlineEmote + "\n"; - }) + if (player.lastLogin > player.lastLogout) { + online.push(player); + } else { + offline.push(player); + } + } - - const embed = new MessageEmbed(); - embed.setTitle("Guild Staff"); - embed.setDescription(embedDesc); - await tmp.delete(); - await message.channel.send(embed) + let embedDesc = ""; + online.forEach((player) => { + embedDesc += "`" + player.displayname + "` " + onlineEmote + "\n"; + }); + offline.forEach((player) => { + embedDesc += "`" + player.displayname + "` " + offlineEmote + "\n"; + }); + + const embed = new MessageEmbed(); + embed.setTitle("Guild Staff"); + embed.setDescription(embedDesc); + await tmp.delete(); + await message.channel.send(embed); + }) + .catch((err) => { + message.channel.send("That command could not be performed at this time. (this may be due to a cooldown). Please try again later!"); + logger.warn(err); + }); }, }; - diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index a06bdd9..fd1b885 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -1,6 +1,7 @@ import { Message, Role, TextChannel } from "discord.js"; import Client from "../structures/Client"; import channels from "../data/calm/channels.json"; +import logger from "../utils/logger/Logger"; module.exports = { name: "unlock", @@ -47,7 +48,7 @@ module.exports = { } if (!channel) { - console.log(`Channel ${channelProperties.name} wasn't found`); + logger.verbose(`Channel ${channelProperties.name} wasn't found`); } else if (channelProperties.membersOnly && fullLock) { channel.updateOverwrite(guildMemberRole, { SEND_MESSAGES: true, ADD_REACTIONS: null }); } else if (channelProperties.public && fullLock) { diff --git a/src/data/calm/staffuuids.ts b/src/data/calm/staffuuids.ts deleted file mode 100644 index 0d33994..0000000 --- a/src/data/calm/staffuuids.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const staffUUID = [ - "3a3c9d90-ab98-47b4-bc5d-73196a65e1d9", // hopez - "5791af76-b724-4f9b-90e7-e7869f1e1aa0", // ohLaike - "6984b889-5ff1-4e10-b549-76751169c91a", // Guitarking257 - "78d0f4bb-658e-4e9c-96ad-be5742a65c94", // Partaken - "3c36c369-c7fc-4305-8fd2-3055c9024d9c", // kiyeo - "c1f69253-3be0-4aae-b37d-ab100e5d3af6", // minik_ - "433b142d-bf96-4db0-9f16-10f7f7912565", // Nitwu - "3028e941-3ecc-4d2b-afed-bbdadc8aaa75", // Purplest - "79990cdf-6357-48f7-8437-565102010d74", // SkillBeatsAll - "a919ee94-adfc-4f0a-af98-20d79409b86d", // InstinctChan - "bf412996-c1e4-424b-880d-1d5788628e95", // Dayfruits - "5ef697d9-35e1-4fe8-a3bb-5a2715cfb02b", // myopic -]; \ No newline at end of file diff --git a/src/events/message.ts b/src/events/message.ts index 70fb16a..e65d36e 100644 --- a/src/events/message.ts +++ b/src/events/message.ts @@ -1,6 +1,8 @@ import { Message, TextChannel } from "discord.js"; +import { loggers } from "winston"; import DiscordClient from "../structures/Client"; import Database from "../utils/database/Database"; +import Logger from "../utils/logger/Logger"; module.exports = async function message(client: DiscordClient, message: Message) { if (message.author.bot || message.channel.type === "dm") return; @@ -54,6 +56,7 @@ module.exports = async function message(client: DiscordClient, message: Message) missingPerms = cmd.permissions.filter((permission) => !message.member.hasPermission(permission)); if (missingPerms.length) return message.channel.send(`You are missing the following permissions required to run this command: ${missingPerms.map((x) => `\`${x}\``).join(", ")}`); } + Logger.verbose(`Running the ${cmd.name} commands for ${message.author.id}`); cmd.run(client, message, args); } }; diff --git a/src/events/ready.ts b/src/events/ready.ts index 8fdd7b4..94bcb82 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,7 +1,6 @@ import Client from "../structures/Client"; +import Logger from "../utils/logger/Logger"; module.exports = async function ready(client: Client) { - console.log(" "); - console.log(`${client.user.tag} is now serving in ${client.guilds.cache.size} guilds!`); - console.log(" "); + Logger.info(`${client.user.tag} is now serving in ${client.guilds.cache.size} guilds!`); }; diff --git a/src/handlers/admin/admincommand.ts b/src/handlers/admin/admincommand.ts index e2ca9a5..40ef423 100644 --- a/src/handlers/admin/admincommand.ts +++ b/src/handlers/admin/admincommand.ts @@ -3,6 +3,7 @@ if (process.env.NODE_ENV !== "production") require("dotenv").config(); import { Message } from "discord.js"; import Client from "../../structures/Client"; import axios from "axios"; +import Logger from "../../utils/logger/Logger"; export default { run: async function run(client: Client, message: Message, args: Array) { @@ -30,8 +31,9 @@ export default { message.channel.send(`StatusCode: ${response.status} | StatusMessage: ${response.statusText}`); }, (error) => { - console.log(error); message.channel.send("There was an error making that request!"); + Logger.error(`Error making request to ${"http://" + ip + ":" + port + "/chat"}!!`); + Logger.error(error); } ); }, diff --git a/src/handlers/admin/admindisablecommand.ts b/src/handlers/admin/admindisablecommand.ts index db1bcec..cf8035a 100644 --- a/src/handlers/admin/admindisablecommand.ts +++ b/src/handlers/admin/admindisablecommand.ts @@ -1,6 +1,7 @@ import { Message } from "discord.js"; import GuildSettings from "../../schemas/GuildSettings"; import Client from "../../structures/Client"; +import Logger from "../../utils/logger/Logger"; export default { run: async function run(client: Client, message: Message, args: Array) { if (args.length < 2) { @@ -33,5 +34,6 @@ export default { guildSettings.disabledCommands.push(cmdname as string); await guildSettings.save(); message.channel.send(`Disabled \`${cmdname}\``); + Logger.info(`Disabled \`${cmdname}\``); }, }; diff --git a/src/handlers/admin/adminenablecommand.ts b/src/handlers/admin/adminenablecommand.ts index f4af9a5..12bfcf3 100644 --- a/src/handlers/admin/adminenablecommand.ts +++ b/src/handlers/admin/adminenablecommand.ts @@ -1,6 +1,7 @@ import { Message } from "discord.js"; import GuildSettings from "../../schemas/GuildSettings"; import Client from "../../structures/Client"; +import Logger from "../../utils/logger/Logger"; export default { run: async function run(client: Client, message: Message, args: Array) { if (args.length < 2) { @@ -33,5 +34,6 @@ export default { } await guildSettings.save(); message.channel.send(`Enabled \`${cmdname}\``); + Logger.info(`Enabled \`${cmdname}\``); }, }; diff --git a/src/handlers/admin/adminmanualchallenge.ts b/src/handlers/admin/adminmanualchallenge.ts index b13fc8a..f949d44 100644 --- a/src/handlers/admin/adminmanualchallenge.ts +++ b/src/handlers/admin/adminmanualchallenge.ts @@ -2,6 +2,7 @@ import { Message, User } from "discord.js"; import Client from "../../structures/Client"; import Challenges from "../../data/calm/challenges/DecemberChallenges.json"; import ChallengeParticipant from "../../schemas/ChallengeParticipant"; +import Logger from "../../utils/logger/Logger"; export default { run: async function run(client: Client, message: Message, args: Array) { @@ -40,10 +41,12 @@ export default { participant.completedChallenges.delete(args[2]); await participant.save(); message.channel.send(`Sucsess! Set ${args[1]}'s challenge #${args[2]} to __FALSE__`); + Logger.verbose(`Set ${args[1]}'s challenge #${args[2]} to FALSE`); if (participant.completedChallenges.size === 0) { let participant = await ChallengeParticipant.findOne({ discordID: args[1] as string }); await participant.delete(); message.channel.send("Document in database for that user has been marked for deletion due to that challenge being the user's last TRUE challenge"); + Logger.verbose(`Deleting ${args[1]}'s challenge participant document as the last entry was manually deleted by ${message.author.id}`); return; } return; @@ -52,6 +55,7 @@ export default { participant.completedChallenges.set(args[2], "true"); await participant.save(); message.channel.send(`Sucsess! Set ${args[1]}'s challenge #${args[2]} to __TRUE__`); + Logger.verbose(`Set ${args[1]}'s challenge #${args[2]} to TRUE`); return; } }, diff --git a/src/handlers/admin/adminsay.ts b/src/handlers/admin/adminsay.ts index 1914df1..5c3f8a2 100644 --- a/src/handlers/admin/adminsay.ts +++ b/src/handlers/admin/adminsay.ts @@ -1,5 +1,6 @@ import { Message, TextChannel } from "discord.js"; import Client from "../../structures/Client"; +import Logger from "../../utils/logger/Logger"; export default { run: async function run(client: Client, message: Message, args: Array) { @@ -15,5 +16,6 @@ export default { const txtchannel = channel as TextChannel; txtchannel.send(text); + Logger.verbose(`Sent message (${text}) in ${txtchannel.name} at request from ${message.author.id}`); }, }; diff --git a/src/handlers/admin/adminsleep.ts b/src/handlers/admin/adminsleep.ts index 788157f..8de6aba 100644 --- a/src/handlers/admin/adminsleep.ts +++ b/src/handlers/admin/adminsleep.ts @@ -1,6 +1,7 @@ import { Message } from "discord.js"; import Database from "../../utils/database/Database"; import Client from "../../structures/Client"; +import Logger from "../../utils/logger/Logger"; export default { run: async function run(client: Client, message: Message, args: Array) { @@ -8,11 +9,13 @@ export default { if (settings.sleep) { settings.sleep = false; settings.save(); - message.channel.send("Turned off sleep mode"); + message.channel.send("Turned off sleep mode."); + Logger.info("Turned off sleep mode"); } else { settings.sleep = true; settings.save(); message.channel.send("Turned on sleep mode. Run c!admin sleep to turn it off"); + Logger.info("Turned on sleep mode."); } }, }; diff --git a/src/structures/Client.ts b/src/structures/Client.ts index 226e974..aac2d73 100644 --- a/src/structures/Client.ts +++ b/src/structures/Client.ts @@ -3,6 +3,7 @@ import path from "path"; import { promisify } from "util"; import Discord from "discord.js"; import Database from "../utils/database/Database"; +import logger from "../utils/logger/Logger"; const readdir = promisify(fs.readdir); @@ -18,25 +19,29 @@ export default class Client extends Discord.Client { partials: ["GUILD_MEMBER", "USER", "MESSAGE", "REACTION", "CHANNEL"], }); - Database.initialize(`mongodb+srv://${process.env.MONGO_USERNAME}:${process.env.MONGO_PASSWORD}@${process.env.MONGO_HOST}/${process.env.MONGO_DBNAME}?retryWrites=true&w=majority`); + logger.verbose("t"); + Database.initialize(`mongodb+srv://${process.env.MONGO_USERNAME}:${process.env.MONGO_PASSWORD}@${process.env.MONGO_HOST}/${process.env.MONGO_DBNAME}?retryWrites=true&w=majority`, this); } async loadEvents(eventsDir: string) { const eventFiles = await readdir(eventsDir); - eventFiles.forEach((file: string, i: number) => { + let e = 0; + eventFiles.forEach((file: string) => { const eventName = file.split(".")[0]; const event = require(path.join(eventsDir, file)); this.on(eventName, event.bind(null, this)); - console.log(`Loaded event: ${eventName}`); + e++; }); + logger.info(`Done loading ${e} commands`); } async loadCommands(commandsDir: string) { const commandFiles = await readdir(commandsDir); - commandFiles.forEach((file: string, i: number) => { + let c = 0; + commandFiles.forEach((file: string) => { const commandName = file.split(".")[0]; const command = require(path.join(commandsDir, file)); this.commands.set(commandName, command); @@ -46,7 +51,8 @@ export default class Client extends Discord.Client { }); } - console.log(`Loaded command: ${commandName} ${command.aliases ? `with aliases: ${command.aliases.join(", ")}` : ""}`); + c++; }); + logger.info(`Done loading ${c} commands.`); } } diff --git a/src/utils/api/HypixelApi.ts b/src/utils/api/HypixelApi.ts index 8bbf0ce..3ef3ddb 100644 --- a/src/utils/api/HypixelApi.ts +++ b/src/utils/api/HypixelApi.ts @@ -1,6 +1,7 @@ if (process.env.NODE_ENV !== "production") require("dotenv").config(); -import axios from "axios"; +import axios, { AxiosError } from "axios"; import * as Interface from "../api/Interfaces"; +import logger from "../logger/Logger"; const KEY = process.env.HYPIXEL_API_KEY; const CALM_GUILD_ID = "5af718d40cf2cbe7a9eeb063"; @@ -9,39 +10,54 @@ let APILastUsed = 0; export default { getGuildStaff: async function (): Promise { - if (!canUseKey()) return undefined; - const res = await axios.get(`https://api.hypixel.net/guild?key=${KEY}&id=${CALM_GUILD_ID}`); - if (res.status !== 200) return undefined; + return new Promise((resolve, reject) => { + if (!canUseKey()) reject("Key overuse."); + axios + .get(`https://api.hypixel.net/guild?key=${KEY}&id=${CALM_GUILD_ID}`) + .then((res) => { + const guild = res.data?.guild || null; - const guild = res.data.guild; - let guildStaffRanks = []; + let guildStaffRanks = []; - guild.ranks.forEach((rank) => { - if (rank.priority >= 4) { - guildStaffRanks.push(rank.name); - } - }); + guild.ranks.forEach((rank) => { + if (rank.priority >= 4) { + guildStaffRanks.push(rank.name); + } + }); - let staffMembers = []; - (guild.members as Interface.IGuildMember[]).forEach((member) => { - if (guildStaffRanks.includes(member.rank) || member.rank === "Guild Master") staffMembers.push(member); - }); + let staffMembers = []; + (guild.members as Interface.IGuildMember[]).forEach((member) => { + if (guildStaffRanks.includes(member.rank) || member.rank === "Guild Master") staffMembers.push(member); + }); - return staffMembers as Interface.IGuildMember[]; + resolve(staffMembers); + }) + .catch((err) => { + reject(err); + logger.warn(err); + }); + }); }, getPlayerFromUUID: async function (uuid: string): Promise { - if(!canUseKey()) return undefined; - const res = await axios.get(`https://api.hypixel.net/player?key=${KEY}&uuid=${uuid}`); - if(res.status !== 200) return undefined; - return res.data.player; + return new Promise((resolve, reject) => { + if (!canUseKey()) reject("Key overuse."); + axios + .get(`https://api.hypixel.net/player?key=${KEY}&uuid=${uuid}`) + .then((res) => { + resolve(res.data.player); + }) + .catch((error) => { + reject(error); + logger.warn(error); + }); + }); }, }; - - // Make sure we don't get ratelimited because we love rate limits function canUseKey(): boolean { + logger.http(`New request for API key. Key has been used ${APIUsage} in the last minute.`); const date = new Date(); if (APILastUsed < date.getMinutes()) { APIUsage = 1; @@ -56,4 +72,3 @@ function canUseKey(): boolean { } } } - diff --git a/src/utils/api/Interfaces.ts b/src/utils/api/Interfaces.ts index d8e148a..d7cdf4c 100644 --- a/src/utils/api/Interfaces.ts +++ b/src/utils/api/Interfaces.ts @@ -1,14 +1,14 @@ -export interface IGuildMember{ - uuid: string, - rank: string, - joined: number, - questParticipation: number, - expHistory: Record +export interface IGuildMember { + uuid: string; + rank: string; + joined: number; + questParticipation: number; + expHistory: Record; } export interface IPlayer { - displayname: string, - uuid: string, - lastLogin: number, - lastLogout: number -} \ No newline at end of file + displayname: string; + uuid: string; + lastLogin: number; + lastLogout: number; +} diff --git a/src/utils/database/Database.ts b/src/utils/database/Database.ts index 76e9cb9..f1efc6b 100644 --- a/src/utils/database/Database.ts +++ b/src/utils/database/Database.ts @@ -2,21 +2,25 @@ import mongoose from "mongoose"; import GuildSettings from "../../schemas/GuildSettings"; import ChallengeParticipant from "../../schemas/ChallengeParticipant"; +import Client from "../../structures/Client"; +import logger from "../logger/Logger"; export default { - initialize: async (url: string) => { + initialize: async (url: string, client: Client) => { await mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true, }); - console.log("Connected to database!"); + logger.info("Connected to database!"); }, getGuildSettings: async (guildid: string) => { let guildSettings = await GuildSettings.findOne({ guildID: guildid }); if (guildSettings === null) { + logger.verbose(`Guild settings did not exist for ${guildid}... creating new document.`); const doc = new GuildSettings({ guildID: guildid }); await doc.save(); + logger.verbose(`Guild settings document for ${guildid} saved.`); guildSettings = doc; } return guildSettings; @@ -25,8 +29,10 @@ export default { getChallengeParticipant: async (discordid: string) => { let participant = await ChallengeParticipant.findOne({ discordID: discordid }); if (participant === null) { + logger.verbose(`Challenge Participant document did not exist for ${discordid}... creating new document.`); const doc = new ChallengeParticipant({ discordID: discordid }); await doc.save(); + logger.verbose(`Challenge Participant document for ${discordid} saved.`); participant = await ChallengeParticipant.findOne({ discordID: discordid }); } return participant; diff --git a/src/utils/logger/Logger.ts b/src/utils/logger/Logger.ts new file mode 100644 index 0000000..a37614b --- /dev/null +++ b/src/utils/logger/Logger.ts @@ -0,0 +1,29 @@ +import winston from "winston"; + +const logger = winston.createLogger({ + format: winston.format.combine(winston.format.timestamp(), winston.format.json()), + transports: [ + new winston.transports.File({ + filename: "./logs/combined.log", + level: "verbose", + }), + new winston.transports.File({ + level: "error", + filename: "./logs/error.log", + }), + ], +}); + +if (process.env.NODE_ENV !== "production") { + const consoleLogFormat = winston.format.printf((info) => { + return `${new Date().toISOString()} [${info.level}] ${info.message}`; + }); + + logger.add( + new winston.transports.Console({ + format: winston.format.combine(winston.format.colorize(), consoleLogFormat), + }) + ); +} + +export default logger; diff --git a/yarn.lock b/yarn.lock index abd876b..eddb8ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,15 @@ # yarn lockfile v1 +"@dabh/diagnostics@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" + integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@discordjs/collection@^0.1.6": version "0.1.6" resolved "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz" @@ -48,6 +57,11 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +async@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" @@ -96,6 +110,52 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.4" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6" + integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colors@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +colorspace@1.1.x: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5" + integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ== + dependencies: + color "3.0.x" + text-hex "1.0.x" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -159,11 +219,31 @@ dotenv@^8.2.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + event-target-shim@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +fast-safe-stringify@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + +fecha@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41" + integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg== + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + follow-redirects@^1.10.0: version "1.13.1" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz" @@ -194,11 +274,21 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" @@ -209,6 +299,22 @@ kareem@2.3.2: resolved "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz" integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +logform@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2" + integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg== + dependencies: + colors "^1.2.1" + fast-safe-stringify "^2.0.4" + fecha "^4.2.0" + ms "^2.1.1" + triple-beam "^1.3.0" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -300,6 +406,11 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz" @@ -312,6 +423,13 @@ once@^1.3.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -327,7 +445,7 @@ process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -readable-stream@^2.3.5: +readable-stream@^2.3.5, readable-stream@^2.3.7: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -340,6 +458,15 @@ readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + regexp-clone@1.0.0, regexp-clone@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz" @@ -370,7 +497,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2: +safe-buffer@5.2.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -397,6 +524,13 @@ sift@7.0.1: resolved "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz" integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + sliced@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz" @@ -422,6 +556,18 @@ sparse-bitfield@^3.0.3: dependencies: memory-pager "^1.0.2" +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" @@ -429,6 +575,16 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + ts-node@^9.1.1: version "9.1.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" @@ -451,11 +607,34 @@ typescript@^4.1.2: resolved "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz" integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +winston-transport@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59" + integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw== + dependencies: + readable-stream "^2.3.7" + triple-beam "^1.2.0" + +winston@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" + integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.1.0" + is-stream "^2.0.0" + logform "^2.2.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.4.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"