use crate::error::MetricsResult;
use crate::ir::{TsPoint, TsValue};
use std::collections::HashMap;
use std::str::FromStr;
#[derive(Deserialize, Debug)]
pub struct TelegrafConfig {
pub endpoints: Vec<String>,
pub port: u64,
pub user: String,
pub password: String,
pub region: String,
}
#[test]
fn test_telegraf_parsing() {
use std::fs::File;
use std::io::Read;
let mut f = File::open("tests/telegraf/telegraf.txt").unwrap();
let mut buff = String::new();
f.read_to_string(&mut buff).unwrap();
let i = parse_telegraf(&buff, None).unwrap();
println!("result: {:#?}", i);
}
fn parse_telegraf(output: &str, point_name: Option<&str>) -> MetricsResult<TsPoint> {
let mut point = TsPoint::new(point_name.unwrap_or("telegraf"), true);
for line in output.lines() {
if line.starts_with('#') {
continue;
}
if line.is_empty() {
continue;
}
let start_index = line.chars().position(|c| c == '{');
let end_index = line.chars().position(|c| c == '}');
let (counter_name, counter_value, tags_text) = match (start_index, end_index) {
(Some(s_index), Some(e_index)) => {
let counter_name = &line[0..s_index];
let counter_value = line[e_index + 1..].trim_start();
let tags_text = &line[s_index + 1..e_index];
(counter_name, counter_value, Some(tags_text))
}
_ => {
let parts: Vec<&str> = line.split_whitespace().collect();
(parts[0], parts[1], None)
}
};
if counter_name.starts_with("go")
|| counter_name.starts_with("disk_inodes")
|| counter_name.starts_with("dm")
|| counter_name.starts_with("disk_used_percent")
|| counter_name.starts_with("net_icmp")
|| counter_name.starts_with("net_udp")
|| counter_name.starts_with("maas_disk")
|| counter_name.starts_with("cpu_usage_guest")
|| counter_name.starts_with("cpu_usage_steal")
{
continue;
}
let mut hmap = HashMap::new();
if let Some(tags_text) = tags_text {
let tags = tags_text.split(',').collect::<Vec<&str>>();
for tag in tags {
let pair = tag.split_terminator('=').collect::<Vec<&str>>();
hmap.insert(pair[0].to_string(), pair[1].to_string());
}
}
if hmap.contains_key("name") {
let n = &hmap["name"].trim_matches('"');
if n.starts_with("loop") || n.starts_with("dm") {
continue;
}
point.add_field(
format!("{}_{}", counter_name.trim_matches('"'), n),
TsValue::Float(f64::from_str(counter_value)?),
);
} else if hmap.contains_key("interface") {
point.add_field(
format!(
"{}_{}",
counter_name.trim_matches('"'),
&hmap["interface"].trim_matches('"')
),
TsValue::Float(f64::from_str(counter_value)?),
);
} else {
point.add_field(counter_name, TsValue::Float(f64::from_str(counter_value)?));
}
}
Ok(point)
}
pub fn get_metrics(
client: &reqwest::Client,
config: &TelegrafConfig,
endpoint: &str,
) -> MetricsResult<TsPoint> {
let url = format!("http://{}:{}/metrics", endpoint, config.port);
let text = client
.get(&url)
.basic_auth(&config.user, Some(&config.password))
.send()?
.error_for_status()?
.text()?;
let points = parse_telegraf(&text, Some("ceph_telegraf"))?;
Ok(points)
}