Bring back stats collection

main
DaXcess 2023-09-19 13:49:32 +02:00
parent 2e273cdcde
commit 1c38067785
No known key found for this signature in database
GPG Key ID: CF78CC72F0FD5EAD
7 changed files with 108 additions and 9 deletions

View File

@ -71,6 +71,14 @@ If you are actively developing Spoticord, you can use the following command to b
cargo run cargo run
``` ```
# Features
As of now, Spoticord has one optional feature: `stats`. This feature enables collecting a few statistics, total and active servers. These statistics will be sent to a redis server, where they then can be read for whatever purpose. If you want to enable this feature, you can do so by running the following command:
```sh
cargo build [--release] --features metrics
```
# MSRV # MSRV
The current minimum supported rust version is `1.65.0`. The current minimum supported rust version is `1.65.0`.

41
Cargo.lock generated
View File

@ -72,9 +72,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.0.5" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -301,6 +301,16 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "combine"
version = "4.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
dependencies = [
"bytes",
"memchr",
]
[[package]] [[package]]
name = "command_attr" name = "command_attr"
version = "0.4.2" version = "0.4.2"
@ -1801,6 +1811,21 @@ dependencies = [
"rand", "rand",
] ]
[[package]]
name = "redis"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f49cdc0bb3f412bf8e7d1bd90fe1d9eb10bc5c399ba90973c14662a27b3f8ba"
dependencies = [
"combine",
"itoa",
"percent-encoding",
"ryu",
"sha1_smol",
"socket2 0.4.9",
"url",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.16" version = "0.2.16"
@ -2243,6 +2268,12 @@ dependencies = [
"digest 0.10.7", "digest 0.10.7",
] ]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]] [[package]]
name = "shannon" name = "shannon"
version = "0.2.0" version = "0.2.0"
@ -2365,9 +2396,9 @@ version = "2.1.0"
dependencies = [ dependencies = [
"dotenv", "dotenv",
"env_logger 0.10.0", "env_logger 0.10.0",
"lazy_static",
"librespot", "librespot",
"log", "log",
"redis",
"reqwest", "reqwest",
"samplerate", "samplerate",
"serde", "serde",
@ -2453,9 +2484,9 @@ dependencies = [
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.2.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [ dependencies = [
"winapi-util", "winapi-util",
] ]

View File

@ -8,12 +8,15 @@ rust-version = "1.65.0"
name = "spoticord" name = "spoticord"
path = "src/main.rs" path = "src/main.rs"
[features]
stats = ["redis"]
[dependencies] [dependencies]
dotenv = "0.15.0" dotenv = "0.15.0"
env_logger = "0.10.0" env_logger = "0.10.0"
lazy_static = { version = "1.4.0", optional = true }
librespot = { version = "0.4.2", default-features = false } librespot = { version = "0.4.2", default-features = false }
log = "0.4.20" log = "0.4.20"
redis = { version = "0.23.3", optional = true }
reqwest = "0.11.20" reqwest = "0.11.20"
samplerate = "0.2.4" samplerate = "0.2.4"
serde = "1.0.188" serde = "1.0.188"
@ -28,4 +31,3 @@ zerocopy = "0.7.5"
[profile.release] [profile.release]
opt-level = 3 opt-level = 3
lto = true lto = true
debug = true

View File

@ -7,7 +7,9 @@ WORKDIR /app
RUN apt-get update && apt-get install -y cmake RUN apt-get update && apt-get install -y cmake
COPY . . COPY . .
RUN cargo install --path .
# Remove `--features stats` if you want to deploy without stats collection
RUN cargo install --path . --features stats
# Runtime # Runtime
FROM debian:buster-slim FROM debian:buster-slim

View File

@ -16,6 +16,7 @@ Spoticord uses environment variables to configure itself. The following variable
Additionally you can configure the following variables: Additionally you can configure the following variables:
- `GUILD_ID`: The ID of the Discord server where this bot will create commands for. This is used during testing to prevent the bot from creating slash commands in other servers, as well as getting the commands quicker. This variable is optional, and if not set, the bot will create commands in all servers it is in (this may take up to 15 minutes). - `GUILD_ID`: The ID of the Discord server where this bot will create commands for. This is used during testing to prevent the bot from creating slash commands in other servers, as well as getting the commands quicker. This variable is optional, and if not set, the bot will create commands in all servers it is in (this may take up to 15 minutes).
- `KV_URL`: The connection URL of a redis-server instance used for storing realtime data. This variable is required when compiling with the `stats` feature.
#### Providing environment variables #### Providing environment variables
You can provide environment variables in a `.env` file at the root of the working directory of Spoticord. You can provide environment variables in a `.env` file at the root of the working directory of Spoticord.

View File

@ -18,6 +18,12 @@ mod player;
mod session; mod session;
mod utils; mod utils;
#[cfg(feature = "stats")]
mod stats;
#[cfg(feature = "stats")]
use crate::stats::StatsManager;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
if std::env::var("RUST_LOG").is_err() { if std::env::var("RUST_LOG").is_err() {
@ -51,6 +57,11 @@ async fn main() {
let token = env::var("DISCORD_TOKEN").expect("a token in the environment"); let token = env::var("DISCORD_TOKEN").expect("a token in the environment");
let db_url = env::var("DATABASE_URL").expect("a database URL in the environment"); let db_url = env::var("DATABASE_URL").expect("a database URL in the environment");
#[cfg(feature = "stats")]
let stats_manager =
StatsManager::new(env::var("KV_URL").expect("a redis URL in the environment"))
.expect("Failed to connect to redis");
let session_manager = SessionManager::new(); let session_manager = SessionManager::new();
// Create client // Create client
@ -73,7 +84,9 @@ async fn main() {
} }
let shard_manager = client.shard_manager.clone(); let shard_manager = client.shard_manager.clone();
let _cache = client.cache_and_http.cache.clone();
#[cfg(feature = "stats")]
let cache = client.cache_and_http.cache.clone();
#[cfg(unix)] #[cfg(unix)]
let mut term: Option<Box<dyn Any + Send>> = Some(Box::new( let mut term: Option<Box<dyn Any + Send>> = Some(Box::new(
@ -88,6 +101,22 @@ async fn main() {
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
tokio::select! { tokio::select! {
_ = tokio::time::sleep(std::time::Duration::from_secs(60)) => {
#[cfg(feature = "stats")]
{
let guild_count = cache.guilds().len();
let active_count = session_manager.get_active_session_count().await;
if let Err(why) = stats_manager.set_server_count(guild_count) {
error!("Failed to update server count: {why}");
}
if let Err(why) = stats_manager.set_active_count(active_count) {
error!("Failed to update active count: {why}");
}
}
}
_ = tokio::signal::ctrl_c() => { _ = tokio::signal::ctrl_c() => {
info!("Received interrupt signal, shutting down..."); info!("Received interrupt signal, shutting down...");

26
src/stats.rs 100644
View File

@ -0,0 +1,26 @@
use redis::{Client, Commands, RedisResult as Result};
#[derive(Clone)]
pub struct StatsManager {
redis: Client,
}
impl StatsManager {
pub fn new(url: impl AsRef<str>) -> Result<Self> {
let redis = Client::open(url.as_ref())?;
Ok(StatsManager { redis })
}
pub fn set_server_count(&self, count: usize) -> Result<()> {
let mut con = self.redis.get_connection()?;
con.set("sc-bot-total-servers", count.to_string())
}
pub fn set_active_count(&self, count: usize) -> Result<()> {
let mut con = self.redis.get_connection()?;
con.set("sc-bot-active-servers", count.to_string())
}
}