#[cfg(feature = "telemetry")]
mod inner {
use std::cmp::Reverse;
use std::path::Path;
use std::sync::atomic::Ordering;
use serde::Serialize;
use crate::registry::CapStats;
#[derive(Serialize)]
struct Entry {
name: &'static str,
file: &'static str,
line: u32,
column: u32,
creation_count: u64,
samples: Vec<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
total_observed: Option<u64>,
}
#[derive(Serialize)]
struct Dump {
version: u32,
stats: Vec<Entry>,
}
fn entry_from((file, line, column): (&'static str, u32, u32), stats: &CapStats) -> Entry {
let samples = stats.samples.snapshot();
let total_observed = stats.samples.total_observed();
Entry {
name: stats.name,
file,
line,
column,
creation_count: stats.creation_count.load(Ordering::Relaxed),
samples,
total_observed: Some(total_observed),
}
}
static DUMP_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
pub fn dump_capacity_stats(path: impl AsRef<Path>) -> std::io::Result<()> {
let _guard = DUMP_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
let mut entries: Vec<Entry> = Vec::new();
crate::registry::registry().scan(|loc, stats| {
entries.push(entry_from(*loc, stats));
});
entries.sort_by_key(|e| Reverse(e.samples.iter().copied().max().unwrap_or(0)));
let dump = Dump {
version: 1,
stats: entries,
};
let path = path.as_ref();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let tmp_path = match path.file_name() {
Some(name) => {
let mut tmp_name = name.to_os_string();
tmp_name.push(format!(".{}.tmp", std::process::id()));
path.with_file_name(tmp_name)
}
None => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"dump_capacity_stats: path has no file name",
))
}
};
{
let f = std::fs::File::create(&tmp_path)?;
serde_json::to_writer_pretty(f, &dump).map_err(std::io::Error::other)?;
}
std::fs::rename(&tmp_path, path)?;
Ok(())
}
}
#[cfg(feature = "telemetry")]
pub use inner::dump_capacity_stats;
#[cfg(not(feature = "telemetry"))]
pub fn dump_capacity_stats<P: AsRef<std::path::Path>>(_path: P) -> std::io::Result<()> {
Ok(())
}