From ae02c9dd9abfbc5dec384c6bbbe2f64ed2e04231 Mon Sep 17 00:00:00 2001 From: Paul Wagner Date: Sat, 11 Jan 2025 14:33:53 +0100 Subject: [PATCH 1/3] handle guild delete and capture guild name --- src/discord.rs | 158 ++++++++++++++++++++++++++++++++++--------------- src/metrics.rs | 1 + 2 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/discord.rs b/src/discord.rs index 2e29618..dd4fb39 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -78,6 +78,7 @@ impl EventHandler for Handler { .guild .get_or_create(&GuildsLabels { guild_id: guild.id.into(), + guild_name: guild.name.clone(), }) .set(1); @@ -205,31 +206,119 @@ impl EventHandler for Handler { } } - async fn guild_delete( + async fn guild_update( &self, _ctx: Context, - incomplete: UnavailableGuild, - _full: Option, + old_data_if_available: Option, + new_data: PartialGuild, ) { - info!(guild_id = incomplete.id.get(), "Guild delete"); + info!(guild_id = new_data.id.get(), "Guild Update"); // Handle `guild` metric + if let Some(guild) = old_data_if_available { + self.metrics_handler.guild.remove(&GuildsLabels { + guild_id: guild.id.into(), + guild_name: guild.name, + }); + } + + // Handle `boost` metric self.metrics_handler - .guild - .get_or_create(&GuildsLabels { - guild_id: incomplete.id.into(), + .boost + .get_or_create(&BoostLabels { + guild_id: new_data.id.into(), }) - .set(0); + .set( + new_data + .premium_subscription_count + .unwrap_or(0) + .try_into() + .expect("expected to fit in i64"), + ); + } + + async fn guild_delete(&self, ctx: Context, incomplete: UnavailableGuild, full: Option) { + info!(guild_id = incomplete.id.get(), "Guild delete"); + + let Some(guild) = full else { + warn!( + guild_id = incomplete.id.get(), + "failed to get guild from cache, this might cause inconsistencies in the metrics" + ); + return; + }; + + // Handle `guild` metric + self.metrics_handler.guild.remove(&GuildsLabels { + guild_id: incomplete.id.into(), + guild_name: guild.name, + }); + + // Handle `channel` metric + for channel in guild.channels.values() { + self.metrics_handler.channel.remove(&ChannelLabels { + guild_id: guild.id.get(), + channel_id: channel.id.get(), + channel_name: channel.name.clone(), + channel_nsfw: channel.nsfw.into(), + channel_type: channel.kind.name().to_string(), + }); + } + + // Handle `boost` metric + self.metrics_handler.boost.remove(&BoostLabels { + guild_id: guild.id.into(), + }); + + // Handle `member` metric + self.metrics_handler.member.remove(&MemberLabels { + guild_id: guild.id.into(), + }); // Handle `bot` metric - self.metrics_handler - .bot - .get_or_create(&BotLabels { - guild_id: incomplete.id.into(), - }) - .set(0); + self.metrics_handler.bot.remove(&BotLabels { + guild_id: incomplete.id.into(), + }); + + for (user_id, presence) in &guild.presences { + // Handle `member_status` metric + self.metrics_handler + .member_status + .remove(&MemberStatusLabels { + guild_id: guild.id.into(), + status: presence.status.name().to_string(), + }); + + // Handle `activity` metric + for activity in &presence.activities { + self.metrics_handler.activity.remove(&ActivityLabels { + guild_id: guild.id.into(), + activity_application_id: activity.application_id.map(Into::into), + activity_name: activity.name.clone(), + }); + } + + // remove user presences from handler cache + self.users.write().await.remove(&(guild.id, *user_id)); + } - // TODO handle other metrics as well! Consider syncing with guild_create "is_new" + // Handle `member_voice` metric + for (_, voice) in guild.voice_states { + if let Some(channel_id) = &voice.channel_id { + let (category, channel) = category_channel(&ctx, guild.id, *channel_id); + self.metrics_handler + .member_voice + .remove(&MemberVoiceLabels { + guild_id: guild.id.into(), + category_id: category.as_ref().map(|ch| ch.get()), + channel_id: channel.into(), + self_stream: voice.self_stream.unwrap_or(false).into(), + self_video: voice.self_video.into(), + self_deaf: voice.self_deaf.into(), + self_mute: voice.self_mute.into(), + }); + } + } } async fn channel_create(&self, _ctx: Context, channel: GuildChannel) { @@ -297,16 +386,13 @@ impl EventHandler for Handler { "Channel delete" ); - self.metrics_handler - .channel - .get_or_create(&ChannelLabels { - guild_id: channel.guild_id.get(), - channel_id: channel.id.get(), - channel_name: channel.name.clone(), - channel_nsfw: channel.nsfw.into(), - channel_type: channel.kind.name().to_string(), - }) - .set(0); + self.metrics_handler.channel.remove(&ChannelLabels { + guild_id: channel.guild_id.get(), + channel_id: channel.id.get(), + channel_name: channel.name.clone(), + channel_nsfw: channel.nsfw.into(), + channel_type: channel.kind.name().to_string(), + }); } async fn guild_member_addition(&self, _ctx: Context, new_member: Member) { @@ -367,28 +453,6 @@ impl EventHandler for Handler { } } - async fn guild_update( - &self, - _ctx: Context, - _old_data_if_available: Option, - new_data: PartialGuild, - ) { - info!(guild_id = new_data.id.get(), "Guild Update"); - - self.metrics_handler - .boost - .get_or_create(&BoostLabels { - guild_id: new_data.id.into(), - }) - .set( - new_data - .premium_subscription_count - .unwrap_or(0) - .try_into() - .expect("expected to fit in i64"), - ); - } - async fn message(&self, ctx: Context, msg: Message) { let Some(guild_id) = msg.guild_id else { // Only tracks guild events diff --git a/src/metrics.rs b/src/metrics.rs index 19d536a..09efe9b 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -54,6 +54,7 @@ impl EncodeLabelValue for Boolean { #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct GuildsLabels { pub guild_id: u64, + pub guild_name: String, } /// [`ChannelLabels`] are the [labels](EncodeLabelSet) for the `channel` metric. From 361164f5873368421220d346288ba4c94b5261bc Mon Sep 17 00:00:00 2001 From: Paul Wagner Date: Sat, 11 Jan 2025 14:35:46 +0100 Subject: [PATCH 2/3] remove renamed channels from response --- src/discord.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/discord.rs b/src/discord.rs index dd4fb39..a1c2510 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -349,16 +349,13 @@ impl EventHandler for Handler { // Decrement old if available if let Some(old) = old { - self.metrics_handler - .channel - .get_or_create(&ChannelLabels { - guild_id: old.guild_id.get(), - channel_id: old.id.get(), - channel_name: old.name.clone(), - channel_nsfw: old.nsfw.into(), - channel_type: old.kind.name().to_string(), - }) - .set(0); + self.metrics_handler.channel.remove(&ChannelLabels { + guild_id: old.guild_id.get(), + channel_id: old.id.get(), + channel_name: old.name.clone(), + channel_nsfw: old.nsfw.into(), + channel_type: old.kind.name().to_string(), + }); } // Increment new From 52ead67ca50171ebe83fcb1bafb501461b89156e Mon Sep 17 00:00:00 2001 From: Paul Wagner Date: Sat, 11 Jan 2025 15:16:57 +0100 Subject: [PATCH 3/3] reorder hooks and use labels builder --- src/discord.rs | 422 +++++++++++++++++++------------------------------ src/metrics.rs | 127 +++++++++++++++ 2 files changed, 291 insertions(+), 258 deletions(-) diff --git a/src/discord.rs b/src/discord.rs index a1c2510..c8326ec 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -70,38 +70,78 @@ fn category_channel( #[async_trait] impl EventHandler for Handler { + async fn channel_create(&self, _ctx: Context, channel: GuildChannel) { + info!( + guild_id = channel.guild_id.get(), + channel_id = channel.id.get(), + "Channel create" + ); + + self.metrics_handler + .channel + .get_or_create(&ChannelLabels::new(&channel)) + .set(1); + } + + async fn channel_delete( + &self, + _ctx: Context, + channel: GuildChannel, + _messages: Option>, + ) { + info!( + guild_id = channel.guild_id.get(), + channel_id = channel.id.get(), + "Channel delete" + ); + + self.metrics_handler + .channel + .remove(&ChannelLabels::new(&channel)); + } + + async fn channel_update(&self, _ctx: Context, old: Option, new: GuildChannel) { + info!( + guild_id = new.guild_id.get(), + channel_id = new.id.get(), + "Channel update" + ); + + // Decrement old if available + if let Some(old) = old { + self.metrics_handler + .channel + .remove(&ChannelLabels::new(&old)); + } + + // Increment new + self.metrics_handler + .channel + .get_or_create(&ChannelLabels::new(&new)) + .set(1); + } + async fn guild_create(&self, ctx: Context, guild: Guild, _is_new: Option) { info!(guild_id = guild.id.get(), "Guild create"); // Handle `guild` metric self.metrics_handler .guild - .get_or_create(&GuildsLabels { - guild_id: guild.id.into(), - guild_name: guild.name.clone(), - }) + .get_or_create(&GuildsLabels::new(&guild)) .set(1); // Handle `channel` metric for channel in guild.channels.values() { self.metrics_handler .channel - .get_or_create(&ChannelLabels { - guild_id: guild.id.get(), - channel_id: channel.id.get(), - channel_name: channel.name.clone(), - channel_nsfw: channel.nsfw.into(), - channel_type: channel.kind.name().to_string(), - }) + .get_or_create(&ChannelLabels::new(channel)) .set(1); } // Handle `boost` metric self.metrics_handler .boost - .get_or_create(&BoostLabels { - guild_id: guild.id.into(), - }) + .get_or_create(&BoostLabels::new(guild.id)) .set( guild .premium_subscription_count @@ -113,9 +153,7 @@ impl EventHandler for Handler { // Handle `member` metric self.metrics_handler .member - .get_or_create(&MemberLabels { - guild_id: guild.id.into(), - }) + .get_or_create(&MemberLabels::new(guild.id)) .set( guild .member_count @@ -129,16 +167,12 @@ impl EventHandler for Handler { let Ok(members) = guild.members(&ctx.http, None, members_after).await else { warn!(guild_id = guild.id.get(), "Failed to count guild bots"); // Remove metric to indicate no bots were counted (successfully) - self.metrics_handler.bot.remove(&BotLabels { - guild_id: guild.id.into(), - }); + self.metrics_handler.bot.remove(&BotLabels::new(guild.id)); break; }; self.metrics_handler .bot - .get_or_create(&BotLabels { - guild_id: guild.id.into(), - }) + .get_or_create(&BotLabels::new(guild.id)) .inc_by( members .iter() @@ -159,21 +193,14 @@ impl EventHandler for Handler { // Handle `member_status` metric self.metrics_handler .member_status - .get_or_create(&MemberStatusLabels { - guild_id: guild.id.into(), - status: presence.status.name().to_string(), - }) + .get_or_create(&MemberStatusLabels::new(guild.id, presence.status)) .inc(); // Handle `activity` metric for activity in &presence.activities { self.metrics_handler .activity - .get_or_create(&ActivityLabels { - guild_id: guild.id.into(), - activity_application_id: activity.application_id.map(Into::into), - activity_name: activity.name.clone(), - }) + .get_or_create(&ActivityLabels::new(guild.id, activity)) .inc(); } @@ -187,56 +214,22 @@ impl EventHandler for Handler { } // Handle `member_voice` metric - for (_, voice) in guild.voice_states { + for voice in guild.voice_states.values() { if let Some(channel_id) = &voice.channel_id { - let (category, channel) = category_channel(&ctx, guild.id, *channel_id); + let (category_id, channel_id) = category_channel(&ctx, guild.id, *channel_id); self.metrics_handler .member_voice - .get_or_create(&MemberVoiceLabels { - guild_id: guild.id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - self_stream: voice.self_stream.unwrap_or(false).into(), - self_video: voice.self_video.into(), - self_deaf: voice.self_deaf.into(), - self_mute: voice.self_mute.into(), - }) + .get_or_create(&MemberVoiceLabels::new( + guild.id, + category_id, + channel_id, + voice, + )) .inc(); } } } - async fn guild_update( - &self, - _ctx: Context, - old_data_if_available: Option, - new_data: PartialGuild, - ) { - info!(guild_id = new_data.id.get(), "Guild Update"); - - // Handle `guild` metric - if let Some(guild) = old_data_if_available { - self.metrics_handler.guild.remove(&GuildsLabels { - guild_id: guild.id.into(), - guild_name: guild.name, - }); - } - - // Handle `boost` metric - self.metrics_handler - .boost - .get_or_create(&BoostLabels { - guild_id: new_data.id.into(), - }) - .set( - new_data - .premium_subscription_count - .unwrap_or(0) - .try_into() - .expect("expected to fit in i64"), - ); - } - async fn guild_delete(&self, ctx: Context, incomplete: UnavailableGuild, full: Option) { info!(guild_id = incomplete.id.get(), "Guild delete"); @@ -249,53 +242,41 @@ impl EventHandler for Handler { }; // Handle `guild` metric - self.metrics_handler.guild.remove(&GuildsLabels { - guild_id: incomplete.id.into(), - guild_name: guild.name, - }); + self.metrics_handler + .guild + .remove(&GuildsLabels::new(&guild)); // Handle `channel` metric for channel in guild.channels.values() { - self.metrics_handler.channel.remove(&ChannelLabels { - guild_id: guild.id.get(), - channel_id: channel.id.get(), - channel_name: channel.name.clone(), - channel_nsfw: channel.nsfw.into(), - channel_type: channel.kind.name().to_string(), - }); + self.metrics_handler + .channel + .remove(&ChannelLabels::new(channel)); } // Handle `boost` metric - self.metrics_handler.boost.remove(&BoostLabels { - guild_id: guild.id.into(), - }); + self.metrics_handler + .boost + .remove(&BoostLabels::new(guild.id)); // Handle `member` metric - self.metrics_handler.member.remove(&MemberLabels { - guild_id: guild.id.into(), - }); + self.metrics_handler + .member + .remove(&MemberLabels::new(guild.id)); // Handle `bot` metric - self.metrics_handler.bot.remove(&BotLabels { - guild_id: incomplete.id.into(), - }); + self.metrics_handler.bot.remove(&BotLabels::new(guild.id)); for (user_id, presence) in &guild.presences { // Handle `member_status` metric self.metrics_handler .member_status - .remove(&MemberStatusLabels { - guild_id: guild.id.into(), - status: presence.status.name().to_string(), - }); + .remove(&MemberStatusLabels::new(guild.id, presence.status)); // Handle `activity` metric for activity in &presence.activities { - self.metrics_handler.activity.remove(&ActivityLabels { - guild_id: guild.id.into(), - activity_application_id: activity.application_id.map(Into::into), - activity_name: activity.name.clone(), - }); + self.metrics_handler + .activity + .remove(&ActivityLabels::new(guild.id, activity)); } // remove user presences from handler cache @@ -303,95 +284,21 @@ impl EventHandler for Handler { } // Handle `member_voice` metric - for (_, voice) in guild.voice_states { + for voice in guild.voice_states.values() { if let Some(channel_id) = &voice.channel_id { - let (category, channel) = category_channel(&ctx, guild.id, *channel_id); + let (category_id, channel_id) = category_channel(&ctx, guild.id, *channel_id); self.metrics_handler .member_voice - .remove(&MemberVoiceLabels { - guild_id: guild.id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - self_stream: voice.self_stream.unwrap_or(false).into(), - self_video: voice.self_video.into(), - self_deaf: voice.self_deaf.into(), - self_mute: voice.self_mute.into(), - }); + .remove(&MemberVoiceLabels::new( + guild.id, + category_id, + channel_id, + voice, + )); } } } - async fn channel_create(&self, _ctx: Context, channel: GuildChannel) { - info!( - guild_id = channel.guild_id.get(), - channel_id = channel.id.get(), - "Channel create" - ); - - self.metrics_handler - .channel - .get_or_create(&ChannelLabels { - guild_id: channel.guild_id.get(), - channel_id: channel.id.get(), - channel_name: channel.name.clone(), - channel_nsfw: channel.nsfw.into(), - channel_type: channel.kind.name().to_string(), - }) - .set(1); - } - - async fn channel_update(&self, _ctx: Context, old: Option, new: GuildChannel) { - info!( - guild_id = new.guild_id.get(), - channel_id = new.id.get(), - "Channel update" - ); - - // Decrement old if available - if let Some(old) = old { - self.metrics_handler.channel.remove(&ChannelLabels { - guild_id: old.guild_id.get(), - channel_id: old.id.get(), - channel_name: old.name.clone(), - channel_nsfw: old.nsfw.into(), - channel_type: old.kind.name().to_string(), - }); - } - - // Increment new - self.metrics_handler - .channel - .get_or_create(&ChannelLabels { - guild_id: new.guild_id.get(), - channel_id: new.id.get(), - channel_name: new.name.clone(), - channel_nsfw: new.nsfw.into(), - channel_type: new.kind.name().to_string(), - }) - .set(1); - } - - async fn channel_delete( - &self, - _ctx: Context, - channel: GuildChannel, - _messages: Option>, - ) { - info!( - guild_id = channel.guild_id.get(), - channel_id = channel.id.get(), - "Channel delete" - ); - - self.metrics_handler.channel.remove(&ChannelLabels { - guild_id: channel.guild_id.get(), - channel_id: channel.id.get(), - channel_name: channel.name.clone(), - channel_nsfw: channel.nsfw.into(), - channel_type: channel.kind.name().to_string(), - }); - } - async fn guild_member_addition(&self, _ctx: Context, new_member: Member) { info!( guild_id = new_member.guild_id.get(), @@ -402,18 +309,14 @@ impl EventHandler for Handler { // Handle `member` metric self.metrics_handler .member - .get_or_create(&MemberLabels { - guild_id: new_member.guild_id.into(), - }) + .get_or_create(&MemberLabels::new(new_member.guild_id)) .inc(); // Handle `bot` metric if new_member.user.bot { self.metrics_handler .bot - .get_or_create(&BotLabels { - guild_id: new_member.guild_id.into(), - }) + .get_or_create(&BotLabels::new(new_member.guild_id)) .inc(); } } @@ -434,22 +337,46 @@ impl EventHandler for Handler { // Handle `member` metric self.metrics_handler .member - .get_or_create(&MemberLabels { - guild_id: guild_id.into(), - }) + .get_or_create(&MemberLabels::new(guild_id)) .dec(); // Handle `bot` metric if user.bot { self.metrics_handler .bot - .get_or_create(&BotLabels { - guild_id: guild_id.into(), - }) + .get_or_create(&BotLabels::new(guild_id)) .dec(); } } + async fn guild_update( + &self, + _ctx: Context, + old_data_if_available: Option, + new_data: PartialGuild, + ) { + info!(guild_id = new_data.id.get(), "Guild Update"); + + // Handle `guild` metric + if let Some(guild) = old_data_if_available { + self.metrics_handler + .guild + .remove(&GuildsLabels::new(&guild)); + } + + // Handle `boost` metric + self.metrics_handler + .boost + .get_or_create(&BoostLabels::new(new_data.id)) + .set( + new_data + .premium_subscription_count + .unwrap_or(0) + .try_into() + .expect("expected to fit in i64"), + ); + } + async fn message(&self, ctx: Context, msg: Message) { let Some(guild_id) = msg.guild_id else { // Only tracks guild events @@ -462,16 +389,12 @@ impl EventHandler for Handler { return; } - let (category, channel) = category_channel(&ctx, guild_id, msg.channel_id); + let (category_id, channel_id) = category_channel(&ctx, guild_id, msg.channel_id); // Handle `message_sent` metric self.metrics_handler .message_sent - .get_or_create(&MessageSentLabels { - guild_id: guild_id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - }) + .get_or_create(&MessageSentLabels::new(guild_id, category_id, channel_id)) .inc(); // Handle `emote_used` metric @@ -483,14 +406,14 @@ impl EventHandler for Handler { self.metrics_handler .emote_used - .get_or_create(&EmoteUsedLabels { - guild_id: guild_id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - reaction: false.into(), - emoji_id: emoji.id.into(), - emoji_name: Some(emoji.name), - }) + .get_or_create(&EmoteUsedLabels::new( + guild_id, + category_id, + channel_id, + false, + emoji.id, + Some(emoji.name), + )) .inc(); } } @@ -514,19 +437,19 @@ impl EventHandler for Handler { return; }; - let (category, channel) = category_channel(&ctx, guild_id, add_reaction.channel_id); + let (category_id, channel_id) = category_channel(&ctx, guild_id, add_reaction.channel_id); // Handle `emote_used` metric self.metrics_handler .emote_used - .get_or_create(&EmoteUsedLabels { - guild_id: guild_id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - reaction: true.into(), - emoji_id: id.into(), - emoji_name: name, - }) + .get_or_create(&EmoteUsedLabels::new( + guild_id, + category_id, + channel_id, + true, + id, + name, + )) .inc(); } @@ -546,21 +469,17 @@ impl EventHandler for Handler { // Handle `member_status` metric (decrement) self.metrics_handler .member_status - .get_or_create(&MemberStatusLabels { - guild_id: guild_id.into(), - status: cached_user.presence.status.name().to_string(), - }) + .get_or_create(&MemberStatusLabels::new( + guild_id, + cached_user.presence.status, + )) .dec(); // Handle `activity` metric (decrement) for activity in &cached_user.presence.activities { self.metrics_handler .activity - .get_or_create(&ActivityLabels { - guild_id: guild_id.into(), - activity_application_id: activity.application_id.map(Into::into), - activity_name: activity.name.clone(), - }) + .get_or_create(&ActivityLabels::new(guild_id, activity)) .dec(); } } @@ -568,21 +487,14 @@ impl EventHandler for Handler { // Handle `member_status` metric self.metrics_handler .member_status - .get_or_create(&MemberStatusLabels { - guild_id: guild_id.into(), - status: new_data.status.name().to_string(), - }) + .get_or_create(&MemberStatusLabels::new(guild_id, new_data.status)) .inc(); // Handle `activity` metric for activity in &new_data.activities { self.metrics_handler .activity - .get_or_create(&ActivityLabels { - guild_id: guild_id.into(), - activity_application_id: activity.application_id.map(Into::into), - activity_name: activity.name.clone(), - }) + .get_or_create(&ActivityLabels::new(guild_id, activity)) .inc(); } @@ -621,20 +533,17 @@ impl EventHandler for Handler { break 'dec; }; - let (category, channel) = category_channel(&ctx, guild_id, *channel_id); + let (category_id, channel_id) = category_channel(&ctx, guild_id, *channel_id); // Handle `member_voice` metric (decrement) self.metrics_handler .member_voice - .get_or_create(&MemberVoiceLabels { - guild_id: guild_id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - self_stream: old.self_stream.unwrap_or(false).into(), - self_video: old.self_video.into(), - self_deaf: old.self_deaf.into(), - self_mute: old.self_mute.into(), - }) + .get_or_create(&MemberVoiceLabels::new( + guild_id, + category_id, + channel_id, + &old, + )) .dec(); } @@ -651,20 +560,17 @@ impl EventHandler for Handler { break 'inc; }; - let (category, channel) = category_channel(&ctx, guild_id, *channel_id); + let (category_id, channel_id) = category_channel(&ctx, guild_id, *channel_id); // Handle `member_voice` metric self.metrics_handler .member_voice - .get_or_create(&MemberVoiceLabels { - guild_id: guild_id.into(), - category_id: category.as_ref().map(|ch| ch.get()), - channel_id: channel.into(), - self_stream: new.self_stream.unwrap_or(false).into(), - self_video: new.self_video.into(), - self_deaf: new.self_deaf.into(), - self_mute: new.self_mute.into(), - }) + .get_or_create(&MemberVoiceLabels::new( + guild_id, + category_id, + channel_id, + &new, + )) .inc(); } } diff --git a/src/metrics.rs b/src/metrics.rs index 09efe9b..87c5443 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -12,6 +12,10 @@ use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::family::Family; use prometheus_client::metrics::gauge::Gauge; use prometheus_client::registry::Registry; +use serenity::all::{ + Activity, ApplicationId, ChannelId, EmojiId, Guild, GuildChannel, GuildId, OnlineStatus, + VoiceState, +}; use std::net::SocketAddr; use std::sync::Arc; use tokio_util::sync::CancellationToken; @@ -57,6 +61,16 @@ pub struct GuildsLabels { pub guild_name: String, } +impl GuildsLabels { + /// Creates a new instance of [`GuildsLabels`]. + pub fn new(guild: &Guild) -> Self { + Self { + guild_id: guild.id.get(), + guild_name: guild.name.clone(), + } + } +} + /// [`ChannelLabels`] are the [labels](EncodeLabelSet) for the `channel` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct ChannelLabels { @@ -67,18 +81,49 @@ pub struct ChannelLabels { pub channel_type: String, } +impl ChannelLabels { + /// Creates a new instance of [`ChannelLabels`]. + pub fn new(channel: &GuildChannel) -> Self { + Self { + guild_id: channel.guild_id.get(), + channel_id: channel.id.get(), + channel_name: channel.name.clone(), + channel_nsfw: Boolean(channel.nsfw), + channel_type: channel.kind.name().to_string(), + } + } +} + /// [`BoostLabels`] are the [labels](EncodeLabelSet) for the `boost` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct BoostLabels { pub guild_id: u64, } +impl BoostLabels { + /// Creates a new instance of [`BoostLabels`]. + pub fn new(guild_id: GuildId) -> Self { + Self { + guild_id: guild_id.get(), + } + } +} + /// [`MemberLabels`] are the [labels](EncodeLabelSet) for the `member` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct MemberLabels { pub guild_id: u64, } +impl MemberLabels { + /// Creates a new instance of [`MemberLabels`]. + pub fn new(guild_id: GuildId) -> Self { + Self { + guild_id: guild_id.get(), + } + } +} + /// [`BotLabels`] are the [labels](EncodeLabelSet) for the `bot` metric. /// /// This metric is not included in the member metric (using a label) as the user bot status has to @@ -89,6 +134,15 @@ pub struct BotLabels { pub guild_id: u64, } +impl BotLabels { + /// Creates a new instance of [`BotLabels`]. + pub fn new(guild_id: GuildId) -> Self { + Self { + guild_id: guild_id.get(), + } + } +} + /// [`MemberStatusLabels`] are the [labels](EncodeLabelSet) for the `member_status` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct MemberStatusLabels { @@ -96,6 +150,16 @@ pub struct MemberStatusLabels { pub status: String, } +impl MemberStatusLabels { + /// Creates a new instance of [`MemberStatusLabels`]. + pub fn new(guild_id: GuildId, status: OnlineStatus) -> Self { + Self { + guild_id: guild_id.get(), + status: status.name().to_string(), + } + } +} + /// [`MemberVoiceLabels`] are the [labels](EncodeLabelSet) for the `member_voice` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct MemberVoiceLabels { @@ -108,6 +172,26 @@ pub struct MemberVoiceLabels { pub self_mute: Boolean, } +impl MemberVoiceLabels { + /// Creates a new instance of [`MemberVoiceLabels`]. + pub fn new( + guild_id: GuildId, + category_id: Option, + channel_id: ChannelId, + voice: &VoiceState, + ) -> Self { + Self { + guild_id: guild_id.get(), + category_id: category_id.map(ChannelId::get), + channel_id: channel_id.get(), + self_stream: voice.self_stream.unwrap_or(false).into(), + self_video: voice.self_video.into(), + self_deaf: voice.self_deaf.into(), + self_mute: voice.self_mute.into(), + } + } +} + /// [`MessageSentLabels`] are the [labels](EncodeLabelSet) for the `message_sent` metric. #[allow(clippy::struct_field_names)] #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] @@ -117,6 +201,17 @@ pub struct MessageSentLabels { pub channel_id: u64, } +impl MessageSentLabels { + /// Creates a new instance of [`MessageSentLabels`]. + pub fn new(guild_id: GuildId, category_id: Option, channel_id: ChannelId) -> Self { + Self { + guild_id: guild_id.get(), + category_id: category_id.map(ChannelId::get), + channel_id: channel_id.get(), + } + } +} + /// [`EmoteUsedLabels`] are the [labels](EncodeLabelSet) for the `emote_used` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct EmoteUsedLabels { @@ -128,6 +223,27 @@ pub struct EmoteUsedLabels { pub emoji_name: Option, } +impl EmoteUsedLabels { + /// Creates a new instance of [`EmoteUsedLabels`]. + pub fn new( + guild_id: GuildId, + category_id: Option, + channel_id: ChannelId, + reaction: bool, + emoji_id: EmojiId, + emoji_name: Option, + ) -> Self { + Self { + guild_id: guild_id.get(), + category_id: category_id.map(ChannelId::get), + channel_id: channel_id.get(), + reaction: Boolean(reaction), + emoji_id: emoji_id.get(), + emoji_name, + } + } +} + /// [`ActivityLabels`] are the [labels](EncodeLabelSet) for the `activity` metric. #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] pub struct ActivityLabels { @@ -136,6 +252,17 @@ pub struct ActivityLabels { pub activity_name: String, } +impl ActivityLabels { + /// Creates a new instance of [`ActivityLabels`]. + pub fn new(guild_id: GuildId, activity: &Activity) -> Self { + Self { + guild_id: guild_id.get(), + activity_application_id: activity.application_id.map(ApplicationId::get), + activity_name: activity.name.clone(), + } + } +} + /// Handler is the [servable](serve) bundle of metrics for the exporter. pub struct Handler { registry: Registry,