197 lines
6.4 KiB
Rust
197 lines
6.4 KiB
Rust
use crate::structs::v3::MetricOutput;
|
|
use serde_json::{Map, Value};
|
|
use prometheus::Gauge;
|
|
use tracing::error;
|
|
use prometheus::Opts;
|
|
use prometheus::GaugeVec;
|
|
|
|
#[derive(Debug)]
|
|
pub enum MetricsValueType {
|
|
Number,
|
|
Array,
|
|
TaggedArray,
|
|
ArrayOfStrings,
|
|
None,
|
|
}
|
|
|
|
pub struct MetricsProcesser;
|
|
|
|
|
|
impl MetricsProcesser {
|
|
|
|
pub fn get_type_of_value(metrics: &MetricOutput) -> MetricsValueType {
|
|
if Self::is_number(metrics) {
|
|
return MetricsValueType::Number;
|
|
}
|
|
else if Self::is_array(metrics) {
|
|
if Self::is_tagged_array(metrics) {
|
|
return MetricsValueType::TaggedArray;
|
|
}
|
|
if Self::is_array_of_string_values(metrics) {
|
|
return MetricsValueType::ArrayOfStrings;
|
|
}
|
|
return MetricsValueType::Array;
|
|
}
|
|
MetricsValueType::None
|
|
}
|
|
|
|
// TODO: i64 and f63 support
|
|
pub fn gauge_from_number(
|
|
metric: &MetricOutput,
|
|
metric_name: &str,
|
|
metric_desc: &str
|
|
) -> Option<Gauge> {
|
|
let gauge = Gauge::new(
|
|
metric_name,
|
|
metric_desc
|
|
);
|
|
|
|
match gauge {
|
|
Ok(gauge) => {
|
|
// let value = metric.value.as_number().unwrap_or({
|
|
// error!("Cannot convert {} metric value to f64 type. Value was set to 0.0", &metric_name);
|
|
// });
|
|
// let value = value.as_f64()
|
|
let val = match metric.value.as_number() {
|
|
Some(val) => {
|
|
val.as_f64().unwrap_or_else(||
|
|
0.0
|
|
)
|
|
},
|
|
None => {
|
|
error!("Cannot convert {} metric value to f64 type. Value was set to 0.0", &metric_name);
|
|
0.0
|
|
},
|
|
};
|
|
gauge.set(val);
|
|
return Some(gauge);
|
|
},
|
|
Err(er) => error!("Cannot create Gauge metric {} due to {}", &metric_name, er),
|
|
}
|
|
|
|
None
|
|
}
|
|
pub fn gauge_from_map_metrics(
|
|
map: &Map<String, Value>,
|
|
service: &str,
|
|
endpoint: &str
|
|
) -> Option<Gauge> {
|
|
let map = map.clone();
|
|
let help: String = map.keys()
|
|
.enumerate()
|
|
.map(|(idx, key)| {
|
|
if idx == 1 {
|
|
return key.to_owned();
|
|
}
|
|
"".to_owned()
|
|
})
|
|
.collect();
|
|
let name = format!("{}_{}_{}", service, endpoint, &help);
|
|
if map.len() > 1 {
|
|
// tagged
|
|
if map.len() > 2 {
|
|
error!("Cannot create Gauge {}. It can be only 1 tag", &name);
|
|
} else {
|
|
let mut label_name = String::new();
|
|
let mut label_value = String::new();
|
|
let mut metric_value = 0.0;
|
|
map.iter()
|
|
.enumerate()
|
|
.for_each(|(idx, (key, value))|{
|
|
if idx == 0 {
|
|
label_name = key.to_owned();
|
|
label_value = value.as_str()
|
|
.unwrap_or("")
|
|
.to_owned();
|
|
} else {
|
|
metric_value = value.as_f64().unwrap_or(0.0)
|
|
}
|
|
});
|
|
let opts = Opts::new(&name, &help);
|
|
let gauge_vec = GaugeVec::new(opts, &[&label_name]);
|
|
match gauge_vec {
|
|
Ok(vec) => {
|
|
// vec.get_metric_with_label_values(vals)
|
|
match vec.get_metric_with_label_values(&[&label_value]) {
|
|
Ok(metric) => {
|
|
metric.set(metric_value); // Устанавливаем значение метрики
|
|
return Some(metric.clone()); // Возвращаем `Gauge`
|
|
},
|
|
Err(er) => {
|
|
error!("Cannot create Gauge {} due to {}", &name, er);
|
|
},
|
|
}
|
|
},
|
|
Err(er) => error!("Cannot create Gauge {} due to {}", &name, er),
|
|
}
|
|
}
|
|
} else {
|
|
// not-tagged
|
|
let metric = Gauge::new(&name, &help);
|
|
match metric {
|
|
Ok(gauge) => {
|
|
let mut value = 0.0;
|
|
map.values()
|
|
.map(|val| val.clone().as_f64())
|
|
.for_each(|val| {
|
|
value = val.unwrap_or(0.0)
|
|
});
|
|
gauge.set(value);
|
|
return Some(gauge);
|
|
},
|
|
Err(er) => {
|
|
error!("Cannot create Gauge {} due to {}", &name, er);
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
pub fn get_value_as_vec_map(metrics: &MetricOutput) -> Vec<Map<String, Value>>{
|
|
let mut vec: Vec<Map<String, Value>> = Vec::new();
|
|
let arr = metrics.value.as_array().unwrap();
|
|
arr.iter()
|
|
.for_each(|a| {
|
|
vec.push(serde_json::from_value(a.clone()).unwrap());
|
|
});
|
|
vec
|
|
}
|
|
pub fn is_array_of_string_values(metrics: &MetricOutput) -> bool {
|
|
let arr = metrics.value.clone();
|
|
let arr = arr.as_array().unwrap();
|
|
let map: Map<String, Value> = serde_json::from_value(
|
|
arr[0].clone()
|
|
).unwrap();
|
|
map.values()
|
|
.all(|val| val.is_string())
|
|
}
|
|
// fn is_valid(metrics: &PrometheusMetrics) -> bool {
|
|
// false
|
|
// }
|
|
fn is_array(metrics: &MetricOutput) -> bool {
|
|
metrics.value.is_array()
|
|
}
|
|
fn is_tagged_array(metrics: &MetricOutput) -> bool {
|
|
let arr = metrics.value.as_array().unwrap();
|
|
let map: Map<String, Value> = serde_json::from_value(arr[0].clone()).unwrap();
|
|
map.len() > 1
|
|
}
|
|
fn is_number(metrics: &MetricOutput) -> bool {
|
|
metrics
|
|
.value.is_number()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
trait IsTaggedArray {
|
|
fn is_tagged_array(&self) -> bool;
|
|
}
|
|
|
|
impl IsTaggedArray for Value {
|
|
fn is_tagged_array(&self) -> bool {
|
|
if let Some(arr) = self.as_array() {
|
|
return arr[0].get("tag_name").is_some();
|
|
}
|
|
false
|
|
}
|
|
} |