use crate::error::Result;
use pprof::Report;
use std::collections::HashMap;
pub async fn pyroscope_ingest<S: AsRef<str>, N: AsRef<str>>(
start: u64,
sample_rate: libc::c_int,
buffer: Vec<u8>,
url: S,
application_name: N,
) -> Result<()> {
if buffer.is_empty() {
return Ok(());
}
let client = reqwest::Client::new();
let s_start = start - start.checked_rem(10).unwrap();
let s_until = s_start + 10;
client
.post(format!("{}/ingest", url.as_ref()))
.header("Content-Type", "binary/octet-stream")
.query(&[
("name", application_name.as_ref()),
("from", &format!("{}", s_start)),
("until", &format!("{}", s_until)),
("format", "folded"),
("sampleRate", &format!("{}", sample_rate)),
("spyName", "pprof-rs"),
])
.body(buffer)
.send()
.await?;
Ok(())
}
pub fn merge_tags_with_app_name(application_name: String, tags: HashMap<String, String>) -> Result<String> {
let mut tags_vec = tags
.into_iter()
.filter(|(k, _)| k != "__name__")
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<String>>();
tags_vec.sort();
let tags_str = tags_vec.join(",");
if !tags_str.is_empty() {
Ok(format!("{}{{{}}}", application_name, tags_str,))
} else {
Ok(application_name)
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use crate::utils::merge_tags_with_app_name;
#[test]
fn merge_tags_with_app_name_with_tags() {
let mut tags = HashMap::new();
tags.insert("env".to_string(), "staging".to_string());
tags.insert("region".to_string(), "us-west-1".to_string());
tags.insert("__name__".to_string(), "reserved".to_string());
assert_eq!(
merge_tags_with_app_name("my.awesome.app.cpu".to_string(), tags).unwrap(),
"my.awesome.app.cpu{env=staging,region=us-west-1}".to_string()
)
}
#[test]
fn merge_tags_with_app_name_without_tags() {
assert_eq!(
merge_tags_with_app_name("my.awesome.app.cpu".to_string(), HashMap::default()).unwrap(),
"my.awesome.app.cpu".to_string()
)
}
}
pub fn fold<W>(report: &Report, with_thread_name: bool, mut writer: W) -> Result<()>
where W: std::io::Write,
{
for (key, value) in report.data.iter() {
if with_thread_name {
if !key.thread_name.is_empty() {
write!(writer, "{};", key.thread_name)?;
} else {
write!(writer, "{:?};", key.thread_id)?;
}
}
let last_frame = key.frames.len() - 1;
for (index, frame) in key.frames.iter().rev().enumerate() {
let last_symbol = frame.len() - 1;
for (index, symbol) in frame.iter().rev().enumerate() {
if index == last_symbol {
write!(writer, "{}", symbol)?;
} else {
write!(writer, "{};", symbol)?;
}
}
if index != last_frame {
write!(writer, ";")?;
}
}
writeln!(writer, " {}", value)?;
}
Ok(())
}