From b0811e4b8bdbd85ed7d2f88a61e15ad6b0253a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sun, 8 Aug 2021 14:37:16 +0200 Subject: [PATCH 1/2] feat: send message to #logs in case of cron error --- src/crons/CommitStrip.ts | 5 +---- src/crons/EpicGames.ts | 3 --- src/framework/Cron.ts | 18 ++++++++++++++++-- src/framework/FormatChecker.ts | 2 -- src/framework/helpers.ts | 13 ++++++++++--- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/crons/CommitStrip.ts b/src/crons/CommitStrip.ts index fe3ec14..2590ea9 100644 --- a/src/crons/CommitStrip.ts +++ b/src/crons/CommitStrip.ts @@ -18,9 +18,6 @@ export default new Cron({ context.logger.info(`Found a new CommitStrip (${latestCommitStrip.id})`); const channel = findTextChannelByName(context.client.channels, 'gif'); - if (!channel) { - throw new Error('found no #gif channel'); - } await channel.send( new MessageEmbed() @@ -90,7 +87,7 @@ async function getRecentCommitStrip(now: Date): Promise { const [strip] = posts; - const stripDate = new Date(strip.date_gmt + ".000Z"); + const stripDate = new Date(strip.date_gmt + '.000Z'); const stripTime = stripDate.getTime(); const nowTime = now.getTime(); const thirtyMinutes = 1000 * 60 * 30; diff --git a/src/crons/EpicGames.ts b/src/crons/EpicGames.ts index 54c13b5..8aa0695 100644 --- a/src/crons/EpicGames.ts +++ b/src/crons/EpicGames.ts @@ -25,9 +25,6 @@ export default new Cron({ } const channel = findTextChannelByName(context.client.channels, 'jeux'); - if (!channel) { - throw new Error('found no #jeux channel'); - } for (const game of games) { context.logger.info(`Found a new offered game (${game.title})`); diff --git a/src/framework/Cron.ts b/src/framework/Cron.ts index 6e4f2bd..8a3940e 100644 --- a/src/framework/Cron.ts +++ b/src/framework/Cron.ts @@ -1,9 +1,10 @@ import { randomUUID } from 'crypto'; import { CronJob, CronTime } from 'cron'; -import { Client } from 'discord.js'; +import { Client, MessageEmbed } from 'discord.js'; import { Logger } from 'pino'; import { Base, BaseConfig } from './Base'; import { Bot } from './Bot'; +import { findTextChannelByName } from './helpers'; export type CronHandler = (context: CronContext) => Promise; @@ -52,8 +53,9 @@ export class Cron extends Base { } private async executeJob(date: Date, bot: Bot) { + const id = randomUUID(); const logger = bot.logger.child({ - id: randomUUID(), + id, type: 'Cron', cronName: this.name, }); @@ -62,6 +64,18 @@ export class Cron extends Base { await this.handler({ date, client: bot.client, logger }); } catch (error) { logger.error(error, 'cron handler error'); + try { + await findTextChannelByName(bot.client.channels, 'logs').send( + new MessageEmbed() + .setTitle('Cron run failed') + .addField('Name', this.name, true) + .addField('Run id', id, true) + .setDescription(`\`\`\`\n${error.stack}\n\`\`\``) + .setColor('RED'), + ); + } catch (error2) { + logger.error(error2, 'failed to send error to #logs'); + } } } diff --git a/src/framework/FormatChecker.ts b/src/framework/FormatChecker.ts index 265d22a..74a3911 100644 --- a/src/framework/FormatChecker.ts +++ b/src/framework/FormatChecker.ts @@ -91,8 +91,6 @@ export class FormatChecker extends Base { } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const channel = findTextChannelByName(message.guild!.channels, 'logs'); - if (channel === undefined) - return logger.fatal('text channel not found: logs'); channel.send(`Bonjour ${author},\n${warningContent}`); } logger.debug('warning message sent'); diff --git a/src/framework/helpers.ts b/src/framework/helpers.ts index 84f8aaa..b9521bf 100644 --- a/src/framework/helpers.ts +++ b/src/framework/helpers.ts @@ -8,10 +8,17 @@ import { export function findTextChannelByName( manager: ChannelManager | GuildChannelManager, name: string, -): TextChannel | undefined { - return manager.cache.find( +): TextChannel { + const channel = manager.cache.find( (channel) => isTextChannel(channel) && channel.name === name, - ) as TextChannel; + ); + if (!channel) { + throw new Error(`found no #${name} channel`); + } + if (!(channel instanceof TextChannel)) { + throw new Error(`channel #${name} is not a text channel`); + } + return channel; } export function isTextChannel(channel: Channel): channel is TextChannel { From 931a2987d46f79920866119a95407d1d4023fe55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sun, 8 Aug 2021 13:01:59 +0200 Subject: [PATCH 2/2] feat: log EpicGames GraphQL responses Refs: https://github.com/ES-Community/bot/issues/36 --- src/crons/EpicGames.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/crons/EpicGames.ts b/src/crons/EpicGames.ts index 8aa0695..e8f24de 100644 --- a/src/crons/EpicGames.ts +++ b/src/crons/EpicGames.ts @@ -1,5 +1,6 @@ import { MessageEmbed } from 'discord.js'; import got from 'got'; +import { Logger } from 'pino'; import { Cron, findTextChannelByName } from '../framework'; @@ -19,7 +20,7 @@ export default new Cron({ 'Vérifie tous les jours à 17h00 (Paris) si Epic Games offre un jeu (promotion gratuite) et alerte dans #jeux', schedule: '0 17 * * *', async handle(context) { - const games = await getOfferedGames(context.date); + const games = await getOfferedGames(context.date, context.logger); if (!games) { return; } @@ -142,7 +143,10 @@ const oneDay = 1000 * 60 * 60 * 24; * were offered between the previous and current cron execution, returns them. * @param now - Current date. Comes from cron schedule. */ -async function getOfferedGames(now: Date): Promise { +async function getOfferedGames( + now: Date, + logger: Logger, +): Promise { const { body } = await got( 'https://www.epicgames.com/graphql', { @@ -158,6 +162,9 @@ async function getOfferedGames(now: Date): Promise { responseType: 'json', }, ); + + logger.info({ data: body.data }, 'Offered games GraphQL response'); + const catalog = body.data.Catalog.searchStore; if (catalog.paging.total === 0) {