diff --git a/crates/kernel/src/prom/mod.rs b/crates/kernel/src/prom/mod.rs index 5da430f3..c4cc745f 100644 --- a/crates/kernel/src/prom/mod.rs +++ b/crates/kernel/src/prom/mod.rs @@ -65,29 +65,51 @@ pub struct QueryResponseDataItem { pub values: Vec<(i64, String)>, } +/// LineSeries is a series of line chart #[derive(Debug, Serialize, Deserialize)] pub struct LineSeries { pub total: i64, pub values: Vec<(i64, i64)>, } +pub type MultiLineSeries = HashMap; + impl LineSeries { - pub fn from(res: &QueryResponse, sequence: Vec) -> Self { - let mut times_data = HashMap::::new(); + pub fn from(res: &QueryResponse, sequence: Vec) -> MultiLineSeries { + let mut all_times_data = HashMap::>::new(); for item in res.data.result.iter() { + let mut times_data = HashMap::::new(); + // convert metric map to vec and sorted, join by "-" as key + let mut keys: Vec = item + .metric + .iter() + .map(|(k, v)| format!("{}-{}", k, v)) + .collect(); + keys.sort(); + let mut key = keys.join("-"); + if key.is_empty() { + key = "metric".to_string(); + } for (t, v) in &item.values { let value = v.parse::().unwrap_or(0.0) as i64; times_data.insert(*t, value); } + all_times_data.insert(key, times_data); } - let mut values = vec![]; - let mut total: i64 = 0; - for t in sequence.iter() { - let value = times_data.get(t).unwrap_or(&0); - values.push((*t * 1000, *value)); // js use milliseconds, t*1000 - total += *value; + + let mut res = MultiLineSeries::new(); + for (k, times_data) in all_times_data.iter() { + let mut values = vec![]; + let mut total: i64 = 0; + for t in sequence.iter() { + let value = times_data.get(t).unwrap_or(&0); + values.push((*t * 1000, *value)); // js use milliseconds, t*1000 + total += *value; + } + let ls = LineSeries { total, values }; + res.insert(k.clone(), ls); } - LineSeries { total, values } + res } } diff --git a/land-server/src/server/dash/overview.rs b/land-server/src/server/dash/overview.rs index b93fe4a2..8d312609 100644 --- a/land-server/src/server/dash/overview.rs +++ b/land-server/src/server/dash/overview.rs @@ -11,6 +11,7 @@ use tracing::info; #[derive(Debug, Serialize)] pub struct ProjectVar { + pub id: i32, pub name: String, pub domain: String, pub domain_full: String, @@ -32,6 +33,7 @@ impl ProjectVar { Ok(projects .into_iter() .map(|p| ProjectVar { + id: p.id, name: p.name.clone(), domain: p.domain.clone(), domain_full: format!("{}.{}", p.domain, domain), @@ -52,6 +54,7 @@ impl ProjectVar { ) -> anyhow::Result { let (domain, protocol) = settings::get_domain_settings().await?; let mut var = ProjectVar { + id: project.id, name: project.name.clone(), domain: project.domain.clone(), domain_full: format!("{}.{}", project.domain, domain), diff --git a/land-server/src/server/dash/traffic.rs b/land-server/src/server/dash/traffic.rs index 529792e9..8fbcb8da 100644 --- a/land-server/src/server/dash/traffic.rs +++ b/land-server/src/server/dash/traffic.rs @@ -53,7 +53,34 @@ pub async fn flows( Extension(user): Extension, Query(q): Query, ) -> Result { - Ok("flows".to_string()) + let now = tokio::time::Instant::now(); + let period = q.get_period(); + let acc = q.account.unwrap_or_default(); + if acc != user.id.to_string() { + return Err(ServerError::forbidden("user id does not match")); + } + let query = get_flow_query(acc, q.project, period.step_word); + debug!( + "query: {}, start:{}, end:{}, step:{}", + query, period.start, period.end, period.step + ); + let params = land_kernel::prom::QueryRangeParams { + query: query.clone(), + step: period.step, + start: period.start, + end: period.end, + }; + let res = land_kernel::prom::query_range(params).await?; + let values = land_kernel::prom::LineSeries::from(&res, period.sequence); + info!( + "query: {}, start:{}, end:{}, step:{}, cost:{}", + query, + period.start, + period.end, + period.step, + now.elapsed().as_millis(), + ); + Ok(Json(values)) } #[derive(Debug, Serialize, Deserialize)] @@ -68,23 +95,13 @@ pub async fn requests( Extension(user): Extension, Query(q): Query, ) -> Result { + let now = tokio::time::Instant::now(); let period = q.get_period(); let acc = q.account.unwrap_or_default(); if acc != user.id.to_string() { return Err(ServerError::forbidden("user id does not match")); } - let query = if let Some(pid) = q.project { - format!( - "increase(req_fn_total{{project_id=\"{}\"}}[{}])", - pid, period.step_word - ) - } else { - format!( - "sum(increase(req_fn_total{{user_id=\"{}\"}}[{}]))", - acc, period.step_word - ) - }; - let now = tokio::time::Instant::now(); + let query = get_request_query(acc, q.project, period.step_word); // end time is now ts with latest 10 decade debug!( "query: {}, start:{}, end:{}, step:{}", @@ -99,13 +116,42 @@ pub async fn requests( let res = land_kernel::prom::query_range(params).await?; let values = land_kernel::prom::LineSeries::from(&res, period.sequence); info!( - "query: {}, start:{}, end:{}, step:{}, values:{}, cost:{}", + "query: {}, start:{}, end:{}, step:{}, cost:{}", query, period.start, period.end, period.step, - values.values.len(), now.elapsed().as_millis(), ); Ok(Json(values)) } + +fn get_flow_query(acc: String, project: Option, step: String) -> String { + let query = if let Some(pid) = project { + format!( + "sum by (project_id,flowtype) (increase(req_fn_bytes_total{{project_id=\"{}\"}}[{}]))", + pid, step, + ) + } else { + format!( + "sum by (user_id,flowtype) (increase(req_fn_bytes_total{{user_id=\"{}\"}}[{}]))", + acc, step, + ) + }; + query +} + +fn get_request_query(acc: String, project: Option, step: String) -> String { + let query = if let Some(pid) = project { + format!( + "sum(increase(req_fn_total{{project_id=\"{}\",status=\"all\"}}[{}]))", + pid, step, + ) + } else { + format!( + "sum(increase(req_fn_total{{user_id=\"{}\",status=\"all\"}}[{}]))", + acc, step, + ) + }; + query +} diff --git a/land-server/tpls/partials/project_traffic.hbs b/land-server/tpls/partials/project_traffic.hbs new file mode 100644 index 00000000..c04f90f5 --- /dev/null +++ b/land-server/tpls/partials/project_traffic.hbs @@ -0,0 +1,25 @@ +
+
+
+

Request counts

+

+
+ Loading... +
+
+
+
+
+
+

Transferred Bytes

+

+
+ Loading... +
+
+
+
+
+ + \ No newline at end of file diff --git a/land-server/tpls/partials/traffic.hbs b/land-server/tpls/partials/traffic.hbs index 705c8a73..89504af6 100644 --- a/land-server/tpls/partials/traffic.hbs +++ b/land-server/tpls/partials/traffic.hbs @@ -16,7 +16,18 @@
-
222
+
+
+
+

Transferred Bytes

+

+
+ Loading... +
+
+
+
+