From 2dc60612831d071c5108b8986d90583ab56ec965 Mon Sep 17 00:00:00 2001 From: Lambo <12111454+LamboCreeper@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:34:19 +0000 Subject: [PATCH] Better Handle Errors & Logging (#283) --- .env.example | 3 +- package-lock.json | 304 +++++++++++++++++- package.json | 1 + src/abstracts/LogMessageDeleteHandler.ts | 28 +- src/event/handlers/LogMessageUpdateHandler.ts | 40 ++- .../handlers/NewUserAuthenticationHandler.ts | 7 +- src/event/handlers/RaidDetectionHandler.ts | 19 +- .../ShowcaseDiscussionThreadHandler.ts | 3 +- src/index.ts | 14 +- src/logger.ts | 44 +++ src/services/MessagePreviewService.ts | 7 +- 11 files changed, 408 insertions(+), 62 deletions(-) create mode 100644 src/logger.ts diff --git a/.env.example b/.env.example index a71ff44..da80058 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ DISCORD_TOKEN=exampleToken ADVENT_OF_CODE_TOKEN=exampleCookieToken -HEALTH_CHECK_URL=https://betteruptime.com/api/v1/heartbeat \ No newline at end of file +HEALTH_CHECK_URL=https://betteruptime.com/api/v1/heartbeat +LOGTAIL_TOKEN=abcdefg12345 diff --git a/package-lock.json b/package-lock.json index c2f92a3..5fe3820 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@codesupport/inherited-config": "^1.0.2", + "@logtail/node": "^0.4.17", "axios": "1.6.0", "axios-cache-interceptor": "^1.3.2", "discord.js": "^14.8.0", @@ -775,6 +776,55 @@ "discord.js": "^14.8.0" } }, + "node_modules/@logtail/core": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/@logtail/core/-/core-0.4.17.tgz", + "integrity": "sha512-8mFF62qMDOxHK+LbdLrnmjQvqG6SsYcfnVXiw1DrSQG+1JlydSBmezJo4kxYBVpnM3ZQYEieeKfZ0jVpzm9NzA==", + "dependencies": { + "@logtail/tools": "^0.4.16", + "@logtail/types": "^0.4.14", + "serialize-error": "^8.1.0" + } + }, + "node_modules/@logtail/node": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/@logtail/node/-/node-0.4.17.tgz", + "integrity": "sha512-O7rtyM4Yx3luRJR7F8gvuYTKwXC81cffFEUGXaI8hvOQHYEjdDnSNQQ/59/1YmOXIgoJ8EKgXTaAgawLNLyvUg==", + "dependencies": { + "@logtail/core": "^0.4.17", + "@logtail/types": "^0.4.14", + "@msgpack/msgpack": "^2.5.1", + "@types/stack-trace": "^0.0.29", + "cross-fetch": "^3.0.4", + "minimatch": "^3.0.4", + "serialize-error": "^8.1.0", + "stack-trace": "^0.0.10" + } + }, + "node_modules/@logtail/tools": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@logtail/tools/-/tools-0.4.16.tgz", + "integrity": "sha512-jHCktK5mbKih8d7//87km+FUzvttdf5QSQ4enisChPjmslFHljs/cp9T0o16AyZ08H5471QWtH5neykZWOY06g==", + "dependencies": { + "@logtail/types": "^0.4.14" + } + }, + "node_modules/@logtail/types": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@logtail/types/-/types-0.4.14.tgz", + "integrity": "sha512-oRAER5vmUyW1rK56EoL+GotVbbCDgttVvg0F9i08WOD6/PjiGcsPH7wNHNYGdvB/KdAXxAhD4+81ZShNKFkZdg==", + "dependencies": { + "js": "^0.1.0" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==", + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -980,6 +1030,11 @@ "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", "dev": true }, + "node_modules/@types/stack-trace": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz", + "integrity": "sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==" + }, "node_modules/@types/ws": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", @@ -1382,8 +1437,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -1398,7 +1452,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1624,6 +1677,17 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.1.1.tgz", + "integrity": "sha512-71Rod2AhcH3JhkBikVpNd0pA+fWsmAaVoti6OR38T76chA7vE3pSerS0Jor4wDw+tOueD2zLVvFOw5H0Rcj7rA==", + "dependencies": { + "keypress": "0.1.x" + }, + "engines": { + "node": ">= 0.6.x" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1633,8 +1697,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/convert-source-map": { "version": "1.9.0", @@ -1677,6 +1740,14 @@ "yarn": ">=1" } }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2884,6 +2955,17 @@ "node": ">=8" } }, + "node_modules/js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/js/-/js-0.1.0.tgz", + "integrity": "sha512-ZBbGYOpact8QAH9RprFWL4RAESYwbDodxiuDjOnzwzzk9pBzKycoifGuUrHHcDixE/eLMKPHRaXenTgu1qXBqA==", + "dependencies": { + "commander": "~1.1.1" + }, + "bin": { + "js": "bin/js" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2951,6 +3033,11 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, + "node_modules/keypress": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA==" + }, "node_modules/keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", @@ -3208,7 +3295,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3413,6 +3499,25 @@ "type-detect": "4.0.8" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -4213,6 +4318,31 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -4371,6 +4501,14 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4543,6 +4681,11 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-api-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", @@ -4850,6 +4993,20 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5630,6 +5787,52 @@ "discord.js": "^14.8.0" } }, + "@logtail/core": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/@logtail/core/-/core-0.4.17.tgz", + "integrity": "sha512-8mFF62qMDOxHK+LbdLrnmjQvqG6SsYcfnVXiw1DrSQG+1JlydSBmezJo4kxYBVpnM3ZQYEieeKfZ0jVpzm9NzA==", + "requires": { + "@logtail/tools": "^0.4.16", + "@logtail/types": "^0.4.14", + "serialize-error": "^8.1.0" + } + }, + "@logtail/node": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/@logtail/node/-/node-0.4.17.tgz", + "integrity": "sha512-O7rtyM4Yx3luRJR7F8gvuYTKwXC81cffFEUGXaI8hvOQHYEjdDnSNQQ/59/1YmOXIgoJ8EKgXTaAgawLNLyvUg==", + "requires": { + "@logtail/core": "^0.4.17", + "@logtail/types": "^0.4.14", + "@msgpack/msgpack": "^2.5.1", + "@types/stack-trace": "^0.0.29", + "cross-fetch": "^3.0.4", + "minimatch": "^3.0.4", + "serialize-error": "^8.1.0", + "stack-trace": "^0.0.10" + } + }, + "@logtail/tools": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@logtail/tools/-/tools-0.4.16.tgz", + "integrity": "sha512-jHCktK5mbKih8d7//87km+FUzvttdf5QSQ4enisChPjmslFHljs/cp9T0o16AyZ08H5471QWtH5neykZWOY06g==", + "requires": { + "@logtail/types": "^0.4.14" + } + }, + "@logtail/types": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@logtail/types/-/types-0.4.14.tgz", + "integrity": "sha512-oRAER5vmUyW1rK56EoL+GotVbbCDgttVvg0F9i08WOD6/PjiGcsPH7wNHNYGdvB/KdAXxAhD4+81ZShNKFkZdg==", + "requires": { + "js": "^0.1.0" + } + }, + "@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5816,6 +6019,11 @@ "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", "dev": true }, + "@types/stack-trace": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz", + "integrity": "sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==" + }, "@types/ws": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", @@ -6078,8 +6286,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "binary-extensions": { "version": "2.2.0", @@ -6091,7 +6298,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6253,6 +6459,14 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.1.1.tgz", + "integrity": "sha512-71Rod2AhcH3JhkBikVpNd0pA+fWsmAaVoti6OR38T76chA7vE3pSerS0Jor4wDw+tOueD2zLVvFOw5H0Rcj7rA==", + "requires": { + "keypress": "0.1.x" + } + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -6262,8 +6476,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "convert-source-map": { "version": "1.9.0", @@ -6294,6 +6507,14 @@ "cross-spawn": "^7.0.1" } }, + "cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "requires": { + "node-fetch": "^2.6.12" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7153,6 +7374,14 @@ "istanbul-lib-report": "^3.0.0" } }, + "js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/js/-/js-0.1.0.tgz", + "integrity": "sha512-ZBbGYOpact8QAH9RprFWL4RAESYwbDodxiuDjOnzwzzk9pBzKycoifGuUrHHcDixE/eLMKPHRaXenTgu1qXBqA==", + "requires": { + "commander": "~1.1.1" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7205,6 +7434,11 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, + "keypress": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA==" + }, "keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", @@ -7406,7 +7640,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7565,6 +7798,14 @@ } } }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -8143,6 +8384,21 @@ } } }, + "serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "requires": { + "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + } + } + }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -8272,6 +8528,11 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -8396,6 +8657,11 @@ "nopt": "~1.0.10" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "ts-api-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", @@ -8614,6 +8880,20 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index cd88c59..71c7f4d 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@codesupport/inherited-config": "^1.0.2", + "@logtail/node": "^0.4.17", "axios": "1.6.0", "axios-cache-interceptor": "^1.3.2", "discord.js": "^14.8.0", diff --git a/src/abstracts/LogMessageDeleteHandler.ts b/src/abstracts/LogMessageDeleteHandler.ts index ddb219e..413dca8 100644 --- a/src/abstracts/LogMessageDeleteHandler.ts +++ b/src/abstracts/LogMessageDeleteHandler.ts @@ -1,23 +1,31 @@ -import {EmbedBuilder, Message, TextChannel, ColorResolvable} from "discord.js"; +import { EmbedBuilder, Message, TextChannel, ColorResolvable } from "discord.js"; import EventHandler from "./EventHandler"; import getConfigValue from "../utils/getConfigValue"; import GenericObject from "../interfaces/GenericObject"; +import { logger } from "../logger"; abstract class LogMessageDeleteHandler extends EventHandler { async sendLog(message: Message): Promise { if (message.content !== "") { - const embed = new EmbedBuilder(); + try { + const embed = new EmbedBuilder(); - embed.setTitle("Message Deleted"); - embed.setDescription(`Author: ${message.author}\nChannel: ${message.channel}`); - embed.addFields([{ name: "Message", value: message.content }]); - embed.setColor(getConfigValue>("EMBED_COLOURS").DEFAULT); + embed.setTitle("Message Deleted"); + embed.setDescription(`Author: ${message.author}\nChannel: ${message.channel}`); + embed.addFields([{ name: "Message", value: message.content }]); + embed.setColor(getConfigValue>("EMBED_COLOURS").DEFAULT); - const logsChannel = message.guild?.channels.cache.find( - channel => channel.id === getConfigValue("LOG_CHANNEL_ID") - ) as TextChannel; + const logsChannel = message.guild?.channels.cache.find( + channel => channel.id === getConfigValue("LOG_CHANNEL_ID") + ) as TextChannel; - await logsChannel?.send({ embeds: [embed] }); + await logsChannel?.send({embeds: [embed]}); + } catch (error) { + logger.error("Failed to send message deletion log", { + messageId: message.id, + channelId: message.channelId + }); + } } } } diff --git a/src/event/handlers/LogMessageUpdateHandler.ts b/src/event/handlers/LogMessageUpdateHandler.ts index c52729b..9e18bb8 100644 --- a/src/event/handlers/LogMessageUpdateHandler.ts +++ b/src/event/handlers/LogMessageUpdateHandler.ts @@ -1,7 +1,8 @@ -import {Events, EmbedBuilder, Message, TextChannel, ColorResolvable} from "discord.js"; +import { Events, EmbedBuilder, Message, TextChannel, ColorResolvable } from "discord.js"; import EventHandler from "../../abstracts/EventHandler"; import getConfigValue from "../../utils/getConfigValue"; import GenericObject from "../../interfaces/GenericObject"; +import { logger } from "../../logger"; class LogMessageUpdateHandler extends EventHandler { constructor() { @@ -17,21 +18,28 @@ class LogMessageUpdateHandler extends EventHandler { return; } - const embed = new EmbedBuilder(); - - embed.setTitle("Message Updated"); - embed.setDescription(`Author: ${oldMessage.author}\nChannel: ${oldMessage.channel}`); - embed.addFields([ - { name: "Old Message", value: oldMessage.content }, - { name: "New Message", value: newMessage.content } - ]); - embed.setColor(getConfigValue>("EMBED_COLOURS").DEFAULT); - - const logsChannel = oldMessage.guild?.channels.cache.find( - channel => channel.id === getConfigValue("LOG_CHANNEL_ID") - ) as TextChannel; - - await logsChannel?.send({ embeds: [embed] }); + try { + const embed = new EmbedBuilder(); + + embed.setTitle("Message Updated"); + embed.setDescription(`Author: ${oldMessage.author}\nChannel: ${oldMessage.channel}`); + embed.addFields([ + { name: "Old Message", value: oldMessage.content }, + { name: "New Message", value: newMessage.content } + ]); + embed.setColor(getConfigValue>("EMBED_COLOURS").DEFAULT); + + const logsChannel = oldMessage.guild?.channels.cache.find( + channel => channel.id === getConfigValue("LOG_CHANNEL_ID") + ) as TextChannel; + + await logsChannel?.send({embeds: [embed]}); + } catch (error) { + logger.error("Failed to send message update log", { + messageId: oldMessage.id, + channelId: oldMessage.channelId + }); + } } } diff --git a/src/event/handlers/NewUserAuthenticationHandler.ts b/src/event/handlers/NewUserAuthenticationHandler.ts index b218c3e..93a72d7 100644 --- a/src/event/handlers/NewUserAuthenticationHandler.ts +++ b/src/event/handlers/NewUserAuthenticationHandler.ts @@ -1,6 +1,7 @@ -import {Events, MessageReaction, RoleResolvable, User} from "discord.js"; +import { Events, MessageReaction, RoleResolvable, User } from "discord.js"; import EventHandler from "../../abstracts/EventHandler"; import getConfigValue from "../../utils/getConfigValue"; +import { logger } from "../../logger"; class NewUserAuthenticationHandler extends EventHandler { constructor() { @@ -15,7 +16,9 @@ class NewUserAuthenticationHandler extends EventHandler { if (isAuthMessage && isAuthEmoji) { const guildMember = await reaction.message.guild?.members.fetch(member); - console.log("User has triggered authentication reaction. Applying member role.", { userId: guildMember?.id }); + logger.info("User has triggered authentication reaction. Applying member role.", { + userId: guildMember?.id + }); await guildMember?.roles.add(getConfigValue("MEMBER_ROLE"), "User has authenticated their account."); } diff --git a/src/event/handlers/RaidDetectionHandler.ts b/src/event/handlers/RaidDetectionHandler.ts index 8cb63a4..7b2d289 100644 --- a/src/event/handlers/RaidDetectionHandler.ts +++ b/src/event/handlers/RaidDetectionHandler.ts @@ -2,6 +2,7 @@ import {ColorResolvable, Events, GuildMember, EmbedBuilder, TextChannel} from "d import EventHandler from "../../abstracts/EventHandler"; import getConfigValue from "../../utils/getConfigValue"; import GenericObject from "../../interfaces/GenericObject"; +import {logger} from "../../logger"; class RaidDetectionHandler extends EventHandler { private joinQueue: GuildMember[] = []; @@ -49,18 +50,16 @@ class RaidDetectionHandler extends EventHandler { Thank you for your cooperation and we apologise for any inconvenience.`); embed.setColor(getConfigValue>("EMBED_COLOURS").WARNING); embed.setTimestamp(); + await generalChannel.send({embeds: [embed]}); - } catch (error: unknown) { - if (error instanceof Error) { - await modChannel.send(`Failed to kick users or empty queue: \n\`${error.message}\``); + } catch (error) { + await modChannel.send( + `Failed to kick users or empty queue: \n\`${error instanceof Error && error.message}\`` + ); - console.error("Failed to kick users or empty queue", { - message: error.message, - error - }); - } else { - console.error(error); - } + logger.error("Failed to kick users or empty queue", { + error + }); } } } diff --git a/src/event/handlers/ShowcaseDiscussionThreadHandler.ts b/src/event/handlers/ShowcaseDiscussionThreadHandler.ts index 03fd2af..faef74f 100644 --- a/src/event/handlers/ShowcaseDiscussionThreadHandler.ts +++ b/src/event/handlers/ShowcaseDiscussionThreadHandler.ts @@ -1,6 +1,7 @@ import { Events, Message } from "discord.js"; import EventHandler from "../../abstracts/EventHandler"; import getConfigValue from "../../utils/getConfigValue"; +import { logger } from "../../logger"; class ShowcaseDiscussionThreadHandler extends EventHandler { constructor() { @@ -17,7 +18,7 @@ class ShowcaseDiscussionThreadHandler extends EventHandler { name: `Discuss ${username}'s Showcase Post` }); } catch (error) { - console.error("Failed to create thread for showcase post", { + logger.error("Failed to create thread for showcase post", { error }); } diff --git a/src/index.ts b/src/index.ts index fb961c9..f0630aa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,15 @@ import App from "./app"; +import { logger } from "./logger"; async function app() { try { await new App().init(); - } catch (error: unknown) { - if (error instanceof Error) { - console.error(error.message, { error }); - } else { - console.error(error); - } + } catch (error) { + logger.error( + error instanceof Error ? error.message : "An error occurred.", + { error } + ); } } -app(); \ No newline at end of file +app(); diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..1a5098c --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,44 @@ +import { Logtail } from "@logtail/node"; + +interface ILogPayload { + userId?: string; + channelId?: string; + messageId?: string; + roleId?: string; + error?: Error | unknown; + + [Key: string]: unknown; +} + +export class Logger { + private readonly logger: Logtail | Console; + + constructor() { + const token = process.env.LOGTAIL_TOKEN; + + if (token) { + this.logger = new Logtail(token); + } else { + this.logger = console; + this.logger.warn("No LOGTAIL_TOKEN environment variable provided. Using console logger."); + } + } + + info(message: string, payload?: ILogPayload) { + this.logger.info(message, payload); + } + + warn(message: string, payload?: ILogPayload) { + this.logger.warn(message, payload); + } + + error(message: string, payload?: ILogPayload) { + this.logger.error(message, payload); + } + + debug(message: string, payload?: ILogPayload) { + this.logger.debug(message, payload); + } +} + +export const logger = new Logger(); diff --git a/src/services/MessagePreviewService.ts b/src/services/MessagePreviewService.ts index 9216e84..bd82bd9 100644 --- a/src/services/MessagePreviewService.ts +++ b/src/services/MessagePreviewService.ts @@ -1,6 +1,7 @@ -import {Message, TextChannel, EmbedBuilder, ColorResolvable, Snowflake} from "discord.js"; +import { Message, TextChannel, EmbedBuilder, ColorResolvable, Snowflake } from "discord.js"; import DateUtils from "../utils/DateUtils"; import getConfigValue from "../utils/getConfigValue"; +import { logger } from "../logger"; class MessagePreviewService { // eslint-disable-next-line no-use-before-define @@ -25,7 +26,7 @@ class MessagePreviewService { if (callingMessage.guild?.available) { const channel = callingMessage.guild.channels.cache.get(msgArray[1]) as TextChannel; const messageToPreview = await channel?.messages.fetch(msgArray[2]) - .catch(error => console.warn("Failed to fetch message to generate preview.", { + .catch(error => logger.warn("Failed to fetch message to generate preview.", { channelId: msgArray[1], messageId: msgArray[2], error @@ -76,4 +77,4 @@ class MessagePreviewService { } } -export default MessagePreviewService; \ No newline at end of file +export default MessagePreviewService;