diff options
-rw-r--r-- | lang/en-US.json | 2 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/bot.ts | 3 | ||||
-rw-r--r-- | src/config/example-options.ts | 3 | ||||
-rw-r--r-- | src/lib/common/Sentry.ts | 12 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClient.ts | 12 | ||||
-rw-r--r-- | src/lib/extensions/global.d.ts | 1 | ||||
-rw-r--r-- | src/lib/utils/BushConstants.ts | 142 | ||||
-rw-r--r-- | src/lib/utils/Config.ts | 1 | ||||
-rw-r--r-- | src/listeners/commands/commandError.ts | 20 | ||||
-rw-r--r-- | src/listeners/commands/commandStarted.ts | 26 | ||||
-rw-r--r-- | src/listeners/other/promiseRejection.ts | 5 | ||||
-rw-r--r-- | src/listeners/other/uncaughtException.ts | 5 | ||||
-rw-r--r-- | src/listeners/other/warning.ts | 5 | ||||
-rw-r--r-- | tsconfig.json | 2 | ||||
-rw-r--r-- | yarn.lock | 1 |
16 files changed, 167 insertions, 74 deletions
diff --git a/lang/en-US.json b/lang/en-US.json index f114f0b..667828e 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -53,4 +53,4 @@ } } } -}
\ No newline at end of file +} diff --git a/package.json b/package.json index 87a384e..2d69f8e 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "simplify-number": "^1.0.0", "source-map-support": "^0.5.20", "tinycolor2": "^1.4.2", + "tslib": "^2.3.1", "typescript": "^4.4.3", "wolfram-alpha-api": "npm:@notenoughupdates/wolfram-alpha-api@latest" }, @@ -2,6 +2,9 @@ import 'module-alias/register'; import 'source-map-support/register'; import config from './config/options'; import { BushClient } from './lib'; +import { Sentry } from './lib/common/Sentry'; +global.__rootdir__ = __dirname || process.cwd(); +new Sentry(); BushClient.init(); void new BushClient(config).start(); diff --git a/src/config/example-options.ts b/src/config/example-options.ts index f6b9dc1..aafda05 100644 --- a/src/config/example-options.ts +++ b/src/config/example-options.ts @@ -8,7 +8,8 @@ export default new Config({ hypixelApiKey: '[API_KEY]', wolframAlphaAppId: '[APP_ID]', imgurClientId: '[CLIENT_ID]', - imgurClientSecret: '[CLIENT_SECRET]' + imgurClientSecret: '[CLIENT_SECRET]', + sentryDsn: 'SENTRY_DSN' }, environment: 'development', owners: [ diff --git a/src/lib/common/Sentry.ts b/src/lib/common/Sentry.ts new file mode 100644 index 0000000..2040536 --- /dev/null +++ b/src/lib/common/Sentry.ts @@ -0,0 +1,12 @@ +import * as SentryNode from '@sentry/node'; +import config from './../../config/options'; + +export class Sentry { + public constructor() { + SentryNode.init({ + dsn: config.credentials.sentryDsn, + environment: config.environment, + tracesSampleRate: 1.0 + }); + } +} diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index 32f43be..4954d8e 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -1,4 +1,5 @@ -import { AkairoClient, ContextMenuCommandHandler } from 'discord-akairo'; +import * as Sentry from '@sentry/node'; +import { AkairoClient, ContextMenuCommandHandler, version as akairoVersion } from 'discord-akairo'; import { Awaitable, Collection, @@ -13,6 +14,7 @@ import { ReplyMessageOptions, Snowflake, Structures, + version as discordJsVersion, WebhookEditMessageOptions } from 'discord.js'; //@ts-ignore: no typings @@ -152,6 +154,7 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re public logger = BushLogger; public constants = BushConstants; public cache = BushCache; + public sentry!: typeof Sentry; public override on<K extends keyof BushClientEvents>( event: K, @@ -322,6 +325,13 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re durationSeconds: durationSecondsTypeCaster, globalUser: globalUserTypeCaster }); + + this.sentry = Sentry; + this.sentry.setTag('process', process.pid.toString()); + this.sentry.setTag('discord.js', discordJsVersion); + this.sentry.setTag('discord-akairo', akairoVersion); + void this.logger.success('startup', `Successfully connected to <<Sentry>>.`, false); + // loads all the handlers const loaders = { commands: this.commandHandler, diff --git a/src/lib/extensions/global.d.ts b/src/lib/extensions/global.d.ts index e10db0a..5274fd2 100644 --- a/src/lib/extensions/global.d.ts +++ b/src/lib/extensions/global.d.ts @@ -4,4 +4,5 @@ import { BushClientUtil } from './discord-akairo/BushClientUtil'; declare global { var client: BushClient; var util: BushClientUtil; + var __rootdir__: string; } diff --git a/src/lib/utils/BushConstants.ts b/src/lib/utils/BushConstants.ts index 64208a1..a4b3108 100644 --- a/src/lib/utils/BushConstants.ts +++ b/src/lib/utils/BushConstants.ts @@ -1,76 +1,5 @@ import { Constants, ConstantsColors } from 'discord.js'; -interface bushColors { - default: '#1FD8F1'; - error: '#EF4947'; - warn: '#FEBA12'; - success: '#3BB681'; - info: '#3B78FF'; - red: '#ff0000'; - blue: '#0055ff'; - aqua: '#00bbff'; - purple: '#8400ff'; - blurple: '#5440cd'; - newBlurple: '#5865f2'; - pink: '#ff00e6'; - green: '#00ff1e'; - darkGreen: '#008f11'; - gold: '#b59400'; - yellow: '#ffff00'; - white: '#ffffff'; - gray: '#a6a6a6'; - lightGray: '#cfcfcf'; - darkGray: '#7a7a7a'; - black: '#000000'; - orange: '#E86100'; - discord: ConstantsColors; -} - -export type PronounCode = - | 'unspecified' - | 'hh' - | 'hi' - | 'hs' - | 'ht' - | 'ih' - | 'ii' - | 'is' - | 'it' - | 'shh' - | 'sh' - | 'si' - | 'st' - | 'th' - | 'ti' - | 'ts' - | 'tt' - | 'any' - | 'other' - | 'ask' - | 'avoid'; -export type Pronoun = - | 'Unspecified' - | 'He/Him' - | 'He/It' - | 'He/She' - | 'He/They' - | 'It/Him' - | 'It/Its' - | 'It/She' - | 'It/They' - | 'She/He' - | 'She/Her' - | 'She/It' - | 'She/They' - | 'They/He' - | 'They/It' - | 'They/She' - | 'They/Them' - | 'Any pronouns' - | 'Other pronouns' - | 'Ask me my pronouns' - | 'Avoid pronouns, use my name'; - const rawCapeUrl = 'https://raw.githubusercontent.com/NotEnoughUpdates/capes/master/'; export class BushConstants { public static emojis = { @@ -564,3 +493,74 @@ export class BushConstants { { name: 'No Support', id: '790247359824396319' } ]; } + +interface bushColors { + default: '#1FD8F1'; + error: '#EF4947'; + warn: '#FEBA12'; + success: '#3BB681'; + info: '#3B78FF'; + red: '#ff0000'; + blue: '#0055ff'; + aqua: '#00bbff'; + purple: '#8400ff'; + blurple: '#5440cd'; + newBlurple: '#5865f2'; + pink: '#ff00e6'; + green: '#00ff1e'; + darkGreen: '#008f11'; + gold: '#b59400'; + yellow: '#ffff00'; + white: '#ffffff'; + gray: '#a6a6a6'; + lightGray: '#cfcfcf'; + darkGray: '#7a7a7a'; + black: '#000000'; + orange: '#E86100'; + discord: ConstantsColors; +} + +export type PronounCode = + | 'unspecified' + | 'hh' + | 'hi' + | 'hs' + | 'ht' + | 'ih' + | 'ii' + | 'is' + | 'it' + | 'shh' + | 'sh' + | 'si' + | 'st' + | 'th' + | 'ti' + | 'ts' + | 'tt' + | 'any' + | 'other' + | 'ask' + | 'avoid'; +export type Pronoun = + | 'Unspecified' + | 'He/Him' + | 'He/It' + | 'He/She' + | 'He/They' + | 'It/Him' + | 'It/Its' + | 'It/She' + | 'It/They' + | 'She/He' + | 'She/Her' + | 'She/It' + | 'She/They' + | 'They/He' + | 'They/It' + | 'They/She' + | 'They/Them' + | 'Any pronouns' + | 'Other pronouns' + | 'Ask me my pronouns' + | 'Avoid pronouns, use my name'; diff --git a/src/lib/utils/Config.ts b/src/lib/utils/Config.ts index 393dd44..81e3a85 100644 --- a/src/lib/utils/Config.ts +++ b/src/lib/utils/Config.ts @@ -61,6 +61,7 @@ interface Credentials { wolframAlphaAppId: string; imgurClientId: string; imgurClientSecret: string; + sentryDsn: string; } type Environment = 'production' | 'beta' | 'development'; diff --git a/src/listeners/commands/commandError.ts b/src/listeners/commands/commandError.ts index 0ef4ebd..61fe206 100644 --- a/src/listeners/commands/commandError.ts +++ b/src/listeners/commands/commandError.ts @@ -1,4 +1,5 @@ import { BushCommandHandlerEvents } from '@lib'; +import { Severity } from '@sentry/types'; import { AkairoMessage, Command, GuildTextBasedChannels } from 'discord-akairo'; import { DMChannel, Formatters, Message, MessageEmbed } from 'discord.js'; import { BushListener } from '../../lib/extensions/discord-akairo/BushListener'; @@ -26,6 +27,25 @@ export default class CommandErrorListener extends BushListener { : (message.channel as GuildTextBasedChannels)!.name; const command = _command ?? message.util?.parsed?.command; + client.sentry.captureException(error, { + level: Severity.Error, + user: { id: message.author.id, username: message.author.tag }, + extra: { + 'command.name': command?.id, + 'message.id': message.id, + 'message.type': message.util.isSlash ? 'slash' : 'normal', + 'message.parsed.content': message.util.parsed!.content, + 'channel.id': + message.channel!.type === 'DM' + ? (message.channel as DMChannel)!.recipient.id + : (message.channel as GuildTextBasedChannels)!.id, + 'channel.name': channel, + 'guild.id': message.guild?.id, + 'guild.name': message.guild?.name, + 'environment': client.config.environment + } + }); + void client.console.error( `${isSlash ? 'slashC' : 'c'}ommandError`, `an error occurred with the <<${command}>> ${isSlash ? 'slash ' : ''}command in <<${channel}>> triggered by <<${ diff --git a/src/listeners/commands/commandStarted.ts b/src/listeners/commands/commandStarted.ts index a9284ed..5d77d66 100644 --- a/src/listeners/commands/commandStarted.ts +++ b/src/listeners/commands/commandStarted.ts @@ -1,4 +1,7 @@ import { BushCommandHandlerEvents, BushListener } from '@lib'; +import { Severity } from '@sentry/types'; +import { GuildTextBasedChannels } from 'discord-akairo'; +import { DMChannel } from 'discord.js'; export default class CommandStartedListener extends BushListener { public constructor() { @@ -9,6 +12,29 @@ export default class CommandStartedListener extends BushListener { }); } public override exec(...[message, command]: BushCommandHandlerEvents['commandStarted']): void { + client.sentry.addBreadcrumb({ + message: `[commandStarted] The ${command.id} was started by ${message.author.tag}.`, + level: Severity.Info, + timestamp: Date.now(), + data: { + 'command.name': command?.id, + 'message.id': message.id, + 'message.type': message.util.isSlash ? 'slash' : 'normal', + 'message.parsed.content': message.util.parsed!.content, + 'channel.id': + message.channel!.type === 'DM' + ? (message.channel as DMChannel)!.recipient.id + : (message.channel as GuildTextBasedChannels)!.id, + 'channel.name': + message.channel!.type === 'DM' + ? (message.channel as DMChannel)!.recipient.tag + : (message.channel as GuildTextBasedChannels)!.name, + 'guild.id': message.guild?.id, + 'guild.name': message.guild?.name, + 'environment': client.config.environment + } + }); + void client.logger.info( 'commandStarted', `The <<${command.id}>> command was used by <<${message.author.tag}>> in ${ diff --git a/src/listeners/other/promiseRejection.ts b/src/listeners/other/promiseRejection.ts index 45e647e..ad16773 100644 --- a/src/listeners/other/promiseRejection.ts +++ b/src/listeners/other/promiseRejection.ts @@ -1,4 +1,5 @@ import { BushListener } from '@lib'; +import { Severity } from '@sentry/node'; import CommandErrorListener from '../commands/commandError'; export default class PromiseRejectionListener extends BushListener { @@ -10,6 +11,10 @@ export default class PromiseRejectionListener extends BushListener { } public override async exec(error: Error) { + client.sentry.captureException(error, { + level: Severity.Error + }); + void client.console.error( 'promiseRejection', `An unhanded promise rejection occurred:\n${typeof error == 'object' ? error.stack : error}`, diff --git a/src/listeners/other/uncaughtException.ts b/src/listeners/other/uncaughtException.ts index 8eb4294..0f8c17c 100644 --- a/src/listeners/other/uncaughtException.ts +++ b/src/listeners/other/uncaughtException.ts @@ -1,4 +1,5 @@ import { BushListener } from '@lib'; +import { Severity } from '@sentry/node'; import CommandErrorListener from '../commands/commandError'; export default class UncaughtExceptionListener extends BushListener { @@ -10,6 +11,10 @@ export default class UncaughtExceptionListener extends BushListener { } public override async exec(error: Error) { + client.sentry.captureException(error, { + level: Severity.Error + }); + void client.console.error( 'uncaughtException', `An uncaught exception occurred:\n${typeof error == 'object' ? error.stack : error}`, diff --git a/src/listeners/other/warning.ts b/src/listeners/other/warning.ts index 51f67ba..bf1488f 100644 --- a/src/listeners/other/warning.ts +++ b/src/listeners/other/warning.ts @@ -1,4 +1,5 @@ import { BushListener } from '@lib'; +import { Severity } from '@sentry/node'; import CommandErrorListener from '../commands/commandError'; export default class WarningListener extends BushListener { @@ -10,6 +11,10 @@ export default class WarningListener extends BushListener { } public override async exec(error: Error) { + client.sentry.captureException(error, { + level: Severity.Warning + }); + void client.console.warn('warning', `A warning occurred:\n${typeof error == 'object' ? error.stack : error}`, false); void client.console.channelError({ embeds: [ diff --git a/tsconfig.json b/tsconfig.json index 6277074..89f0f5f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,6 +19,8 @@ "baseUrl": "./", "useUnknownInCatchVariables": false, "forceConsistentCasingInFileNames": true, + "noEmitHelpers": true, + "importHelpers": true, "paths": { "src/*": ["./src/*"], "@lib": ["./src/lib"], @@ -865,6 +865,7 @@ __metadata: simplify-number: ^1.0.0 source-map-support: ^0.5.20 tinycolor2: ^1.4.2 + tslib: ^2.3.1 typescript: ^4.4.3 wolfram-alpha-api: "npm:@notenoughupdates/wolfram-alpha-api@latest" languageName: unknown |