Skip to content

Commit

Permalink
Add code block parameter for logging
Browse files Browse the repository at this point in the history
  • Loading branch information
QuantumManiac committed Feb 4, 2024
1 parent 8915a89 commit b0be0f2
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 70 deletions.
33 changes: 25 additions & 8 deletions src/classes/SlackLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,51 @@ export class SlackLogger {
return SlackLogger.instance;
}

private async log(level: LogLevel, message: string, logToConsole = true): Promise<void> {
private async log(
level: LogLevel,
message: string,
codeBlockContent: string = "",
logToConsole = true,
): Promise<void> {
const formattedMessage = this.formatMessage(level, message);

if (logToConsole) {
if (level === LogLevel.ERROR) {
console.error(formattedMessage);
console.error(codeBlockContent);
} else {
console.log(formattedMessage);
console.log(codeBlockContent);
}
}

await postMessage(this.slackClient, loggingChannel, formattedMessage);
let formattedSlackMessage = formattedMessage;

if (codeBlockContent) {
formattedSlackMessage += "\n" + this.formatcodeBlockContent(codeBlockContent);
}

await postMessage(this.slackClient, loggingChannel, formattedSlackMessage);
}

async info(message: string, logToConsole = true): Promise<void> {
await this.log(LogLevel.INFO, message, logToConsole);
async info(message: string, codeBlockContent: string = "", logToConsole = true): Promise<void> {
await this.log(LogLevel.INFO, message, codeBlockContent, logToConsole);
}

async warning(message: string, logToConsole = true): Promise<void> {
await this.log(LogLevel.WARNING, message, logToConsole);
async warning(message: string, codeBlockContent: string = "", logToConsole = true): Promise<void> {
await this.log(LogLevel.WARNING, message, codeBlockContent, logToConsole);
}

async error(message: string, logToConsole = true): Promise<void> {
await this.log(LogLevel.ERROR, message, logToConsole);
async error(message: string, codeBlockContent: string = "", logToConsole = true): Promise<void> {
await this.log(LogLevel.ERROR, message, codeBlockContent, logToConsole);
}

private formatMessage(level: LogLevel, message: string): string {
const timeStamp = new Date().toISOString();
return `[${timeStamp}] [${level}] ${message}`;
}

private formatcodeBlockContent(codeBlockContent: string): string {
return `\`\`\`${codeBlockContent}\`\`\``;
}
}
19 changes: 12 additions & 7 deletions src/listeners/commands/helpCommand.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { slackBotToken } from "../../utils/env";
import { Middleware, SlackCommandMiddlewareArgs } from "@slack/bolt";
import { logCommandUsed } from "../../utils/logging";
import { postEphemeralMessage } from "../../utils/slack";
import { SlackLogger } from "../../classes/SlackLogger";

const message = `For more information, check out <https://github.com/waterloo-rocketry/minerva-rewrite/blob/main/README.md|minerva's README>.`;

export const helpCommandHandler: Middleware<SlackCommandMiddlewareArgs> = async ({ command, ack, client }) => {
await ack();
await logCommandUsed(command);

await client.chat.postEphemeral({
token: slackBotToken,
channel: command.channel_id,
user: command.user_id,
text: message,
});
try {
await postEphemeralMessage(client, command.channel_id, command.user_id, message);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
throw new Error("This is a test error");
} catch (error) {
SlackLogger.getInstance().error(
`Failed to post ephemeral message to user \`${command.user_id}\` with error:`,
error,
);
}
};
10 changes: 7 additions & 3 deletions src/utils/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ export function filterSlackChannelsFromNames(names: string[], channels: SlackCha
const channel = channels.find((channel) => channel.name === name);
// If a channel with a given name is not found, it logs an error and continues to the next name.
if (channel == undefined) {
SlackLogger.getInstance().warning(`could not find channel with name ${name} when filtering channels`);
SlackLogger.getInstance().warning(`could not find channel with name \`${name}\` when filtering channels`);
continue;
}

// If a channel has an undefined name or id, it logs an error and continues to the next channel.
if (channel.name == undefined || channel.id == undefined) {
SlackLogger.getInstance().error(`channel with name ${name} has undefined name or id. This should not happen.`);
SlackLogger.getInstance().error(
`channel with name \`${name}\` has undefined name or id. This should not happen.`,
);
continue;
}

Expand Down Expand Up @@ -79,7 +81,9 @@ export async function getAllSlackChannels(client: WebClient): Promise<SlackChann

for (const channel of channels.channels ?? []) {
if (channel.name == undefined || channel.id == undefined) {
SlackLogger.getInstance().error(`channel with name ${name} has undefined name or id. This should not happen.`);
SlackLogger.getInstance().error(
`channel with name \`${channel.name}\` has undefined name or id. This should not happen.`,
);
continue;
}

Expand Down
18 changes: 7 additions & 11 deletions src/utils/eventReminders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export async function remindUpcomingEvent(
);

SlackLogger.getInstance().info(
`Sent reminder for event "${event.title}" at ${event.start} to #${event.minervaEventMetadata.channel.name} and ${singleChannelGuestsMessaged} single channel guests`,
`Sent reminder for event \`${event.title}\` at \`${event.start}\` to \`${event.minervaEventMetadata.channel.name}\` and ${singleChannelGuestsMessaged} single channel guests`,
);
}

Expand All @@ -131,10 +131,8 @@ export async function postReminderToChannel(
});
} catch (error) {
SlackLogger.getInstance().error(
`Failed to post reminder message to channel ${channel.name} with error:
\`\`\`
${error}
\`\`\``,
`Failed to post reminder message to channel \`${channel.name}\` with error:`,
String(error),
);
return;
}
Expand All @@ -150,12 +148,10 @@ ${error}
try {
await addReactionToMessage(client, channel.id, emoji, timestamp);
} catch (error) {
SlackLogger.getInstance()
.error(`Failed to add reaction ${emoji} to message ${timestamp} in ${channel.name} with error
\`\`\`
${error}
\`\`\`
`);
SlackLogger.getInstance().error(
`Failed to add reaction \`${emoji}\` to message \`${timestamp}\` in \`${channel.name}\` with error:`,
String(error),
);
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import { SlackLogger } from "../classes/SlackLogger";
*/
export async function logCommandUsed(command: SlashCommand): Promise<void> {
await SlackLogger.getInstance().info(
`${command.user_name} used the ${command.command} command in ${command.channel_name}`,
`\`${command.user_name}\` used the \`${command.command}\` command in \`${command.channel_name}\``,
);
}
119 changes: 79 additions & 40 deletions src/utils/slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,48 @@ export async function postMessage(
...options,
});
} catch (error) {
throw `Failed to post message to channel ${channel.name} with error ${error}`;
SlackLogger.getInstance().error(`Failed to post message to channel \`${channel.name}\` with error:`, String(error));
throw error;
}

return res;
}

/**
* Posts an ephemeral message to a Slack channel
* @param client Slack Web API client
* @param channel The Slack channel to post the message to
* @param user The Slack user to post the message to
* @param text The text of the message to post
* @param options Optional arguments for the message as per https://api.slack.com/methods/chat.postEphemeral#args
* @returns A promise that resolves to the response from the Slack API
*/
export async function postEphemeralMessage(
client: WebClient,
channel: string,
user: string,
text: string,
options?: ChatPostMessageOptionalArgs,
): Promise<ChatPostMessageResponse | undefined> {
let res: ChatPostMessageResponse | undefined = undefined;
try {
res = await client.chat.postEphemeral({
channel: channel,
user: user,
text: text,
...options,
});

return res;
} catch (error) {
SlackLogger.getInstance().error(
`Failed to post ephemeral message to channel \`${channel}\` with error:`,
String(error),
);
throw error;
}
}

// https://api.slack.com/methods/emoji.list
/**
* Retrieves all custom emoji from a Slack workspace.
Expand All @@ -65,11 +101,7 @@ export async function getAllEmoji(client: WebClient): Promise<string[]> {
}
return Object.keys(result.emoji);
} catch (error) {
SlackLogger.getInstance().error(`Failed to get emojis for workspace:
\`\`\`
${error}
\`\`\`
`);
SlackLogger.getInstance().error(`Failed to get emojis for workspace:`, String(error));
throw error;
}
}
Expand All @@ -88,24 +120,29 @@ export async function getAllSlackUsers(
let cursor: string | undefined = undefined;

while (true) {
const response = await client.users.list({
limit: 900,
cursor: cursor,
});

if (response.members) {
response.members.forEach((user) => {
if (user.deleted == includeDeactivatedMembers) {
const userType: UserType = determineUserType(user);
const newGuest = new SlackUser(user.real_name as string, user.id as string, userType);
usersList.push(newGuest);
}
try {
const response = await client.users.list({
limit: 900,
cursor: cursor,
});
}

cursor = response.response_metadata?.next_cursor;
if (!cursor) {
break;
if (response.members) {
response.members.forEach((user) => {
if (user.deleted == includeDeactivatedMembers) {
const userType: UserType = determineUserType(user);
const newGuest = new SlackUser(user.real_name as string, user.id as string, userType);
usersList.push(newGuest);
}
});
}

cursor = response.response_metadata?.next_cursor;
if (!cursor) {
break;
}
} catch (error) {
SlackLogger.getInstance().error(`Failed to get users from workspace:`, String(error));
throw error;
}
}
return usersList;
Expand Down Expand Up @@ -140,12 +177,8 @@ export async function getChannelMembers(client: WebClient, channelId: string): P
}
return members.length > 0 ? members : undefined;
} catch (error) {
SlackLogger.getInstance().error(`Failed to get members for channel with id ${channelId}:
\`\`\`
${error}
\`\`\`
`);
return undefined;
SlackLogger.getInstance().error(`Failed to get members for channel with id \`${channelId}\`:`, String(error));
throw error;
}
}

Expand All @@ -167,11 +200,19 @@ export function addReactionToMessage(
// Convert timestamp to string if it's a number
const timestampStr = typeof timestamp === "number" ? timestamp.toString() : timestamp;

return client.reactions.add({
channel,
name: emoji,
timestamp: timestampStr,
});
try {
return client.reactions.add({
channel,
name: emoji,
timestamp: timestampStr,
});
} catch (error) {
SlackLogger.getInstance().error(
`Failed to add reaction \`${emoji}\` to message \`${timestampStr}\` in \`${channel}\`:`,
String(error),
);
throw error;
}
}

/**
Expand All @@ -193,13 +234,11 @@ export async function getMessagePermalink(
message_ts: timestamp,
});
} catch (error) {
SlackLogger.getInstance()
.error(`Error fetching message permalink for message with timestamp ${timestamp} in ${channel}:
\`\`\`
${error}
\`\`\`
`);
return;
SlackLogger.getInstance().error(
`Error fetching message permalink for message with timestamp \`${timestamp}\` in \`${channel}\`:`,
String(error),
);
throw error;
}

if (res?.ok) {
Expand Down

0 comments on commit b0be0f2

Please sign in to comment.