diff --git a/backend/.sqlx/query-1c67cce8cdf6e56752643d6382ebaab76e24581009ca5e8d8b5ce3f199b689ab.json b/backend/.sqlx/query-cdfc8e9af4414b7ee7525bc74d9caad74b5479c64337c401a7a9550a3434cdfa.json similarity index 74% rename from backend/.sqlx/query-1c67cce8cdf6e56752643d6382ebaab76e24581009ca5e8d8b5ce3f199b689ab.json rename to backend/.sqlx/query-cdfc8e9af4414b7ee7525bc74d9caad74b5479c64337c401a7a9550a3434cdfa.json index 8d6a62b4e8..2a16736617 100644 --- a/backend/.sqlx/query-1c67cce8cdf6e56752643d6382ebaab76e24581009ca5e8d8b5ce3f199b689ab.json +++ b/backend/.sqlx/query-cdfc8e9af4414b7ee7525bc74d9caad74b5479c64337c401a7a9550a3434cdfa.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT COUNT(*) FROM worker_ping WHERE ping_at > NOW() - INTERVAL '5 minutes'", + "query": "SELECT COUNT(*) FROM worker_ping WHERE ping_at > NOW() - INTERVAL '2 minutes'", "describe": { "columns": [ { @@ -16,5 +16,5 @@ null ] }, - "hash": "1c67cce8cdf6e56752643d6382ebaab76e24581009ca5e8d8b5ce3f199b689ab" + "hash": "cdfc8e9af4414b7ee7525bc74d9caad74b5479c64337c401a7a9550a3434cdfa" } diff --git a/backend/.sqlx/query-e70835de2b70a01a2e85f44f3cb80f41288d8e68b762de80ae724ed69ef1908c.json b/backend/.sqlx/query-e70835de2b70a01a2e85f44f3cb80f41288d8e68b762de80ae724ed69ef1908c.json new file mode 100644 index 0000000000..abd991317d --- /dev/null +++ b/backend/.sqlx/query-e70835de2b70a01a2e85f44f3cb80f41288d8e68b762de80ae724ed69ef1908c.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT author.count as author_count, operator.count as operator_count FROM (SELECT count(*)::INT FROM usr where usr.operator IS false) as author, (SELECT count(*)::INT FROM usr where usr.operator IS true) as operator", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "author_count", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "operator_count", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + null + ] + }, + "hash": "e70835de2b70a01a2e85f44f3cb80f41288d8e68b762de80ae724ed69ef1908c" +} diff --git a/backend/src/main.rs b/backend/src/main.rs index a112772d14..87e0155b89 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -9,7 +9,6 @@ use gethostname::gethostname; use git_version::git_version; use rand::Rng; -use serde::Deserialize; use sqlx::{postgres::PgListener, Pool, Postgres}; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -30,7 +29,7 @@ use windmill_common::{ RETENTION_PERIOD_SECS_SETTING, }, stats::schedule_stats, - utils::rd_string, + utils::{rd_string, Mode}, worker::{reload_custom_tags_setting, WORKER_GROUP}, DB, METRICS_ADDR, METRICS_ENABLED, }; @@ -59,14 +58,6 @@ mod monitor; #[cfg(feature = "pg_embed")] mod pg_embed; -#[derive(Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum Mode { - Worker, - Server, - Standalone, -} - #[tokio::main] async fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); @@ -460,10 +451,8 @@ Windmill Community Edition {GIT_VERSION} Ok(()) as anyhow::Result<()> }; - if mode == Mode::Server || mode == Mode::Standalone { - let instance_name = rd_string(8); - schedule_stats(&db, instance_name, &HTTP_CLIENT).await; - } + let instance_name = rd_string(8); + schedule_stats(instance_name, mode, &db, &HTTP_CLIENT).await; futures::try_join!(shutdown_signal, server_f, metrics_f, workers_f, monitor_f)?; } else { diff --git a/backend/windmill-api/src/settings.rs b/backend/windmill-api/src/settings.rs index 984ec2a171..4747775721 100644 --- a/backend/windmill-api/src/settings.rs +++ b/backend/windmill-api/src/settings.rs @@ -172,7 +172,13 @@ pub async fn get_global_setting( pub async fn send_stats(Extension(db): Extension, authed: ApiAuthed) -> Result { require_super_admin(&db, &authed.email).await?; - windmill_common::stats::send_stats(&"manual".to_string(), &HTTP_CLIENT, &db).await?; + windmill_common::stats::send_stats( + &"manual".to_string(), + &windmill_common::utils::Mode::Server, + &HTTP_CLIENT, + &db, + ) + .await?; Ok("Sent stats".to_string()) } diff --git a/backend/windmill-common/src/stats.rs b/backend/windmill-common/src/stats.rs index 991aae0aff..352936e663 100644 --- a/backend/windmill-common/src/stats.rs +++ b/backend/windmill-common/src/stats.rs @@ -4,7 +4,7 @@ use crate::{ error::{to_anyhow, Result}, global_settings::DISABLE_STATS_SETTING, scripts::ScriptLang, - utils::{get_uid, GIT_VERSION}, + utils::{get_uid, Mode, GIT_VERSION}, DB, }; use chrono::Utc; @@ -34,15 +34,22 @@ pub async fn get_disable_stats_setting(db: &DB) -> bool { false } -pub async fn schedule_stats(db: &DB, instance_name: String, http_client: &reqwest::Client) -> () { +pub async fn schedule_stats( + instance_name: String, + mode: Mode, + db: &DB, + http_client: &reqwest::Client, +) -> () { let http_client = http_client.clone(); let db = db.clone(); tokio::spawn(async move { + tokio::time::sleep(tokio::time::Duration::from_secs(180)).await; + loop { let disabled = get_disable_stats_setting(&db).await; if !disabled { tracing::info!("Sending stats"); - let result = send_stats(&instance_name, &http_client, &db).await; + let result = send_stats(&instance_name, &mode, &http_client, &db).await; if result.is_err() { tracing::info!("Error sending stats: {}", result.err().unwrap()); } else { @@ -83,6 +90,7 @@ struct JobsUsage { pub async fn send_stats( instance_name: &String, + mode: &Mode, http_client: &reqwest::Client, db: &DB, ) -> Result<()> { @@ -108,13 +116,32 @@ pub async fn send_stats( .collect::>(); let workers_usage = sqlx::query!( - "SELECT COUNT(*) FROM worker_ping WHERE ping_at > NOW() - INTERVAL '5 minutes'" + "SELECT COUNT(*) FROM worker_ping WHERE ping_at > NOW() - INTERVAL '2 minutes'" ) .fetch_one(db) .await? .count .unwrap_or(0); + let users_count = sqlx::query!("SELECT author.count as author_count, operator.count as operator_count FROM (SELECT count(*)::INT FROM usr where usr.operator IS false) as author, (SELECT count(*)::INT FROM usr where usr.operator IS true) as operator") + .fetch_one(db) + .await?; + + let vcpus = std::process::Command::new("cat") + .args(["/sys/fs/cgroup/cpu.max"]) + .output() + .ok() + .map(|o| { + String::from_utf8_lossy(&o.stdout) + .to_string() + .split(" ") + .map(|s| s.to_string()) + .collect::>() + .get(0) + .map(|s| s.to_string()) + }) + .flatten(); + let payload = serde_json::json!({ "uid": uid, "version": GIT_VERSION, @@ -122,8 +149,16 @@ pub async fn send_stats( "jobs_usage": jobs_usage, "login_type_usage": login_type_usage, "workers_usage": workers_usage, + "users_usage": { + "author_count": users_count.author_count.unwrap_or(0), + "operator_count": users_count.operator_count.unwrap_or(0), + }, + "mode": mode, + "vcpus": vcpus, }); + tracing::info!("Sending stats: {:#?}", payload); + let request = http_client .post("https://hub.windmill.dev/stats") .body(serde_json::to_string(&payload).map_err(to_anyhow)?) diff --git a/backend/windmill-common/src/utils.rs b/backend/windmill-common/src/utils.rs index 2d81473fc9..9c2d5ff267 100644 --- a/backend/windmill-common/src/utils.rs +++ b/backend/windmill-common/src/utils.rs @@ -162,3 +162,11 @@ pub async fn get_uid(db: &DB) -> Result { Ok(uid) } + +#[derive(Serialize, Deserialize, PartialEq, Clone)] +#[serde(rename_all = "lowercase")] +pub enum Mode { + Worker, + Server, + Standalone, +} diff --git a/frontend/src/lib/components/InstanceSettings.svelte b/frontend/src/lib/components/InstanceSettings.svelte index c8d8f2a83a..0a980e9e63 100644 --- a/frontend/src/lib/components/InstanceSettings.svelte +++ b/frontend/src/lib/components/InstanceSettings.svelte @@ -18,7 +18,7 @@ import CustomOauth from './CustomOauth.svelte' import { AlertTriangle, Plus } from 'lucide-svelte' import CustomSso from './CustomSso.svelte' - import AuthentikSetting from "$lib/components/AuthentikSetting.svelte"; + import AuthentikSetting from '$lib/components/AuthentikSetting.svelte' export let tab: string = 'Core' export let hideTabs: boolean = false @@ -177,8 +177,10 @@
  • version
  • number and total duration of jobs
  • +
  • accounts usage
  • login type usage
  • workers usage
  • +
  • vcpus usage
{#if $enterpriseLicense} @@ -216,7 +218,7 @@ {#each Object.keys(oauths) as k} - {#if !['authentik','google', 'microsoft', 'github', 'gitlab', 'jumpcloud', 'okta', 'keycloak', 'slack'].includes(k) && 'login_config' in oauths[k]} + {#if !['authentik', 'google', 'microsoft', 'github', 'gitlab', 'jumpcloud', 'okta', 'keycloak', 'slack'].includes(k) && 'login_config' in oauths[k]} {#if oauths[k]}
@@ -281,7 +283,7 @@
{#each Object.keys(oauths) as k} - {#if !['authentik','google', 'microsoft', 'github', 'gitlab', 'jumpcloud', 'okta', 'keycloak', 'slack'].includes(k) && !('login_config' in oauths[k])} + {#if !['authentik', 'google', 'microsoft', 'github', 'gitlab', 'jumpcloud', 'okta', 'keycloak', 'slack'].includes(k) && !('login_config' in oauths[k])} {#if oauths[k]}