Skip to content

Commit bcb71a2

Browse files
authored
Add error logging (#14)
* Create send error helper * Add commandname * Install uuid * Add uuid to error embed * Add metadata to error log * Edit reply of command with error * Add error handling to relevant functions * Log error to console
1 parent 2b2653e commit bcb71a2

File tree

11 files changed

+117
-26
lines changed

11 files changed

+117
-26
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
"lodash": "^4.17.21",
1919
"mixpanel": "^0.17.0",
2020
"pg": "^8.10.0",
21-
"topgg-autoposter": "^2.0.1"
21+
"topgg-autoposter": "^2.0.1",
22+
"uuid": "^9.0.0"
2223
},
2324
"devDependencies": {
2425
"@types/jest": "^29.5.0",
2526
"@types/lodash": "^4.14.191",
2627
"@types/pg": "^8.6.6",
28+
"@types/uuid": "^9.0.1",
2729
"auto": "^10.43.0",
2830
"eslint": "^8.36.0",
2931
"eslint-plugin-unused-imports": "^2.0.0",

src/App.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Client, GatewayIntentBits } from 'discord.js';
22
import { BOT_TOKEN } from './config/environment';
33
import { registerEventHandlers } from './events/events';
4+
import { sendErrorLog } from './utils/helpers';
45

56
const app: Client = new Client({
67
intents: [GatewayIntentBits.Guilds],
@@ -11,7 +12,7 @@ const initialize = async (): Promise<void> => {
1112
await app.login(BOT_TOKEN);
1213
registerEventHandlers({ app });
1314
} catch (error) {
14-
throw error;
15+
sendErrorLog({ error });
1516
}
1617
};
1718

src/commands/hello/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { SlashCommandBuilder } from 'discord.js';
2+
import { sendErrorLog } from '../../utils/helpers';
23
import { AppCommand, AppCommandOptions } from '../commands';
34

45
export default {
@@ -8,7 +9,7 @@ export default {
89
await interaction.deferReply();
910
await interaction.editReply('Hello!');
1011
} catch (error) {
11-
console.log(error);
12+
sendErrorLog({ error, interaction });
1213
}
1314
},
1415
} as AppCommand;

src/events/events.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Client } from 'discord.js';
22
import fs from 'fs';
33
import path from 'path';
44
import { AppCommands, getApplicationCommands } from '../commands/commands';
5+
import { sendErrorLog } from '../utils/helpers';
56

67
const appCommands = getApplicationCommands();
78

@@ -19,8 +20,7 @@ export function registerEventHandlers({ app }: Props): void {
1920
const loadModules = (directoryPath: string) => {
2021
fs.readdir(directoryPath, { withFileTypes: true }, (error, files) => {
2122
if (error) {
22-
//TODO: Replace with error handling
23-
console.log(error);
23+
sendErrorLog({ error });
2424
}
2525
files &&
2626
files.forEach((file) => {

src/events/guildCreate/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Guild, WebhookClient } from 'discord.js';
22
import { isEmpty } from 'lodash';
33
import { GUILD_NOTIFICATION_WEBHOOK_URL, USE_DATABASE } from '../../config/environment';
44
import { insertNewGuild } from '../../services/database';
5-
import { serverNotificationEmbed } from '../../utils/helpers';
5+
import { sendErrorLog, serverNotificationEmbed } from '../../utils/helpers';
66
import { EventModule } from '../events';
77

88
export default function ({ app }: EventModule) {
@@ -19,8 +19,7 @@ export default function ({ app }: EventModule) {
1919
});
2020
}
2121
} catch (error) {
22-
//TODO: Add error handling
23-
console.log(error);
22+
sendErrorLog({ error });
2423
}
2524
});
2625
}

src/events/guildDelete/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Guild, WebhookClient } from 'discord.js';
22
import { isEmpty } from 'lodash';
33
import { GUILD_NOTIFICATION_WEBHOOK_URL, USE_DATABASE } from '../../config/environment';
44
import { deleteGuild } from '../../services/database';
5-
import { serverNotificationEmbed } from '../../utils/helpers';
5+
import { sendErrorLog, serverNotificationEmbed } from '../../utils/helpers';
66
import { EventModule } from '../events';
77

88
export default function ({ app }: EventModule) {
@@ -19,8 +19,7 @@ export default function ({ app }: EventModule) {
1919
});
2020
}
2121
} catch (error) {
22-
//TODO: Add error handling
23-
console.log(error);
22+
sendErrorLog({ error });
2423
}
2524
});
2625
}

src/events/interactionCreate/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CacheType, Interaction } from 'discord.js';
22
import { AppCommands } from '../../commands/commands';
3+
import { sendErrorLog } from '../../utils/helpers';
34
import { EventModule } from '../events';
45

56
export default function ({ app, appCommands }: EventModule) {
@@ -13,9 +14,8 @@ export default function ({ app, appCommands }: EventModule) {
1314
command && (await command.execute({ interaction, app }));
1415
}
1516
//Maybe add buttons, selections and modal handlers here eventually
16-
} catch (errors) {
17-
//TODO: Add error handling
18-
console.log(errors);
17+
} catch (error) {
18+
sendErrorLog({ error });
1919
}
2020
});
2121
}

src/events/ready/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { REST, Routes } from 'discord.js';
22
import { AppCommands } from '../../commands/commands';
33
import { BOT_TOKEN, ENV, GUILD_IDS, USE_DATABASE } from '../../config/environment';
44
import { createGuildTable, populateGuilds } from '../../services/database';
5+
import { sendErrorLog } from '../../utils/helpers';
56
import { EventModule } from '../events';
67

78
const rest = new REST({ version: '9' }).setToken(BOT_TOKEN);
@@ -32,8 +33,7 @@ const registerApplicationCommands = async (commands?: AppCommands) => {
3233
console.log('Successfully registered global application commands');
3334
}
3435
} catch (error) {
35-
//TODO: Add error handling
36-
console.log(error);
36+
sendErrorLog({ error });
3737
}
3838
};
3939

src/services/database.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Collection, Guild } from 'discord.js';
22
import { Pool, PoolClient } from 'pg';
33
import { databaseConfig } from '../config/database';
4+
import { sendErrorLog } from '../utils/helpers';
45
const pool: Pool = new Pool(databaseConfig);
56

67
type GuildRecord = {
@@ -21,8 +22,7 @@ export async function createGuildTable() {
2122
await client.query('COMMIT');
2223
} catch (error) {
2324
await client.query('ROLLBACK');
24-
console.log(error);
25-
//TODO: Add error handling
25+
sendErrorLog({ error });
2626
} finally {
2727
client.release();
2828
}
@@ -38,8 +38,7 @@ export async function getGuilds() {
3838
return allGuilds;
3939
} catch (error) {
4040
await client.query('ROLLBACK');
41-
console.log(error);
42-
//TODO: Add error handling
41+
sendErrorLog({ error });
4342
} finally {
4443
client.release();
4544
}
@@ -57,8 +56,7 @@ export async function populateGuilds(existingGuilds: Collection<string, Guild>)
5756
}
5857
});
5958
} catch (error) {
60-
console.log(error);
61-
//TODO: Add error handling
59+
sendErrorLog({ error });
6260
}
6361
}
6462
export async function insertNewGuild(newGuild: Guild) {
@@ -77,8 +75,7 @@ export async function insertNewGuild(newGuild: Guild) {
7775
await client.query('COMMIT');
7876
} catch (error) {
7977
await client.query('ROLLBACK');
80-
console.log(error);
81-
//TODO: Add error handling
78+
sendErrorLog({ error });
8279
} finally {
8380
client.release();
8481
}
@@ -94,7 +91,7 @@ export async function deleteGuild(existingGuild: Guild) {
9491
await client.query('COMMIT');
9592
} catch (error) {
9693
await client.query('ROLLBACK');
97-
console.log(error);
94+
sendErrorLog({ error });
9895
} finally {
9996
client.release();
10097
}

src/utils/helpers.ts

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
import { APIEmbed, Client, Guild } from 'discord.js';
1+
import {
2+
APIEmbed,
3+
Client,
4+
CommandInteraction,
5+
Guild,
6+
GuildChannel,
7+
WebhookClient,
8+
} from 'discord.js';
9+
import { capitalize, isEmpty } from 'lodash';
10+
import { ERROR_NOTIFICATION_WEBHOOK_URL } from '../config/environment';
11+
import { v4 as uuid } from 'uuid';
12+
13+
export const codeMark = (text: string) => {
14+
return '`' + text + '`';
15+
};
216

317
export const serverNotificationEmbed = async ({
418
app,
@@ -44,3 +58,71 @@ export const serverNotificationEmbed = async ({
4458
};
4559
return embed;
4660
};
61+
62+
export const sendErrorLog = async ({
63+
error,
64+
interaction,
65+
}: {
66+
error: any;
67+
interaction?: CommandInteraction;
68+
}) => {
69+
console.error(error);
70+
const errorID = uuid();
71+
if (interaction) {
72+
const errorEmbed = {
73+
description: `Oops something went wrong! D:\n\nError: ${
74+
error.message ? codeMark(error.message) : codeMark('Unexpected Error')
75+
}\nError ID: ${codeMark(errorID)}`,
76+
color: 16711680,
77+
};
78+
await interaction.editReply({ embeds: [errorEmbed] });
79+
}
80+
if (ERROR_NOTIFICATION_WEBHOOK_URL && !isEmpty(ERROR_NOTIFICATION_WEBHOOK_URL)) {
81+
const interactionChannel = interaction?.channel as GuildChannel | undefined;
82+
const notificationEmbed: APIEmbed = {
83+
title: interaction ? `Error | ${capitalize(interaction.commandName)} Command` : 'Error',
84+
color: 16711680,
85+
description: `uuid: ${errorID}\nError: ${error.message ? error.message : 'Unexpected Error'}`,
86+
fields: interaction
87+
? [
88+
{
89+
name: 'User',
90+
value: interaction.user.username,
91+
inline: true,
92+
},
93+
{
94+
name: 'User ID',
95+
value: interaction.user.id,
96+
inline: true,
97+
},
98+
{
99+
name: 'Channel',
100+
value: interactionChannel ? interactionChannel.name : '-',
101+
inline: true,
102+
},
103+
{
104+
name: 'Channel ID',
105+
value: interaction.channelId,
106+
inline: true,
107+
},
108+
{
109+
name: 'Guild',
110+
value: interaction.guild ? interaction.guild.name : '-',
111+
inline: true,
112+
},
113+
{
114+
name: 'Guild ID',
115+
value: interaction.guildId ? interaction.guildId : '-',
116+
inline: true,
117+
},
118+
]
119+
: undefined,
120+
};
121+
const notificationWebhook = new WebhookClient({ url: ERROR_NOTIFICATION_WEBHOOK_URL });
122+
await notificationWebhook.send({
123+
embeds: [notificationEmbed],
124+
username: 'My App Error Notification',
125+
avatarURL: '',
126+
});
127+
}
128+
};

0 commit comments

Comments
 (0)