feat: adds uptime telemetry (#6545)

* feat: adds uptime telemetry

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: remove seconds and minutes

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
This commit is contained in:
dennis zhuang
2025-07-17 17:55:28 +08:00
committed by GitHub
parent 8237646055
commit 37dc057423

View File

@@ -16,8 +16,8 @@ use std::env;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::sync::{Arc, LazyLock};
use std::time::{Duration, SystemTime};
use common_runtime::error::{Error, Result};
use common_runtime::{BoxedTaskFunction, RepeatedTask, TaskFunction};
@@ -31,6 +31,9 @@ pub const TELEMETRY_URL: &str = "https://telemetry.greptimestats.com/db/otel/sta
/// The local installation uuid cache file
const UUID_FILE_NAME: &str = ".greptimedb-telemetry-uuid";
/// System start time for uptime calculation
static START_TIME: LazyLock<SystemTime> = LazyLock::new(SystemTime::now);
/// The default interval of reporting telemetry data to greptime cloud
pub static TELEMETRY_INTERVAL: Duration = Duration::from_secs(60 * 30);
/// The default connect timeout to greptime cloud.
@@ -103,6 +106,8 @@ struct StatisticData {
pub nodes: Option<i32>,
/// The local installation uuid
pub uuid: String,
/// System uptime range (e.g., "hours", "days", "weeks")
pub uptime: String,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
@@ -171,6 +176,25 @@ fn print_anonymous_usage_data_disclaimer() {
info!("https://docs.greptime.com/reference/telemetry");
}
/// Format uptime duration into a general time range string
/// Returns privacy-friendly descriptions like "hours", "days", etc.
fn format_uptime() -> String {
let uptime_duration = START_TIME.elapsed().unwrap_or(Duration::ZERO);
let total_seconds = uptime_duration.as_secs();
if total_seconds < 86400 {
"hours".to_string()
} else if total_seconds < 604800 {
"days".to_string()
} else if total_seconds < 2629746 {
"weeks".to_string()
} else if total_seconds < 31556952 {
"months".to_string()
} else {
"years".to_string()
}
}
pub fn default_get_uuid(working_home: &Option<String>) -> Option<String> {
let temp_dir = env::temp_dir();
@@ -260,6 +284,7 @@ impl GreptimeDBTelemetry {
mode: self.statistics.get_mode(),
nodes: self.statistics.get_nodes().await,
uuid,
uptime: format_uptime(),
};
if let Some(client) = self.client.as_ref() {
@@ -294,7 +319,9 @@ mod tests {
use reqwest::{Client, Response};
use tokio::spawn;
use crate::{default_get_uuid, Collector, GreptimeDBTelemetry, Mode, StatisticData};
use crate::{
default_get_uuid, format_uptime, Collector, GreptimeDBTelemetry, Mode, StatisticData,
};
static COUNT: AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
@@ -438,6 +465,7 @@ mod tests {
assert_eq!(build_info().commit, body.git_commit);
assert_eq!(Mode::Standalone, body.mode);
assert_eq!(1, body.nodes.unwrap());
assert!(!body.uptime.is_empty());
let failed_statistic = Box::new(FailedStatistic);
let failed_report = GreptimeDBTelemetry::new(
@@ -477,4 +505,18 @@ mod tests {
assert_eq!(uuid, default_get_uuid(&Some(working_home.clone())));
assert_eq!(uuid, default_get_uuid(&Some(working_home)));
}
#[test]
fn test_format_uptime() {
let uptime = format_uptime();
assert!(!uptime.is_empty());
// Should be a valid general time range (no specific numbers)
assert!(
uptime == "hours"
|| uptime == "days"
|| uptime == "weeks"
|| uptime == "months"
|| uptime == "years"
);
}
}