Prometheus Exporter 開発で Discord サーバ運営の健全化を図る
自分は Discord でゲームコミュニティを運営していて Discord サーバを管理しています。運営のために必要な情報を集めようと思い、ボット開発や Prometheus Exporter の開発をしています。この記事では Prometheus Exporter について書こうと思います。 Discord Exporter の概要 Discord Exporter は、Discord サーバの統計情報を Prometheus メトリクスとしてエクスポートするツールです。メンバー数と各チャネルのメッセージ数を収集し Prometheus Exporter としてメトリクスを Promehteus Server に提供するものです。 https://github.com/jedipunkz/discord-exporter コードの要所説明 Discord Exporter の主要な処理を解説していきます。 Discord API 呼び出し処理 メンバー情報の取得 updateMemberCount 関数では、Discord の GuildMembers API エンドポイントを呼び出してメンバー情報を取得します。API の制限により最大1000件単位でメンバーを取得し、取得したメンバー数を Prometheus のゲージメトリクスに設定します。 func updateMemberCount(s *discordgo.Session, guildID string) { members, err := s.GuildMembers(guildID, "", 1000) if err != nil { log.Printf("Error fetching members: %v", err) return } memberCountGauge.Set(float64(len(members))) log.Printf("Updated member count: %d", len(members)) } メッセージカウント処理 countChannelMessages 関数では、チャネルのメッセージを段階的に取得します。ChannelMessages API で100件ずつメッセージを取得し、最終メッセージの ID を次のリクエストのアンカーとして使用することで、全メッセージを数え上げるまでループ処理を行います。 func countChannelMessages(s *discordgo.Session, channelID string) (int, error) { count := 0 lastID := "" for { messages, err := s.ChannelMessages(channelID, 100, lastID, "", "") if err != nil { return 0, err } if len(messages) == 0 { break } count += len(messages) lastID = messages[len(messages)-1].ID } return count, nil } メトリクス収集の実装 並行処理とレート制限 Discord API への過度な呼び出しを防ぐため、セマフォを使用した並行処理制御を実装しています。最大5チャネルを同時処理できるように制限し各ゴルーチンが処理前にセマフォを取得、完了後に解放する仕組みで効率的かつ安全に複数チャネルを並行処理します。 ...