use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::sync::Arc;
use bytes::Bytes;
use conjure_error::Error;
use http::HeaderValue;
use once_cell::sync::Lazy;
use parking_lot::Mutex;
use regex::Regex;
pub(crate) mod diagnostic_types;
pub(crate) mod endpoint;
#[cfg(feature = "jemalloc")]
pub(crate) mod heap_profile;
#[cfg(feature = "jemalloc")]
pub(crate) mod heap_stats;
pub(crate) mod metric_names;
#[cfg(target_os = "linux")]
pub(crate) mod thread_dump;
static TYPE_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"([a-z0-9]+\.)+v[0-9]+").unwrap());
pub trait Diagnostic {
fn type_(&self) -> &str;
fn content_type(&self) -> HeaderValue;
fn safe_loggable(&self) -> bool;
fn result(&self) -> Result<Bytes, Error>;
}
pub struct DiagnosticRegistry {
diagnostics: Mutex<HashMap<String, Arc<dyn Diagnostic + Sync + Send>>>,
}
impl Default for DiagnosticRegistry {
fn default() -> Self {
Self::new()
}
}
impl DiagnosticRegistry {
pub fn new() -> Self {
DiagnosticRegistry {
diagnostics: Mutex::new(HashMap::new()),
}
}
pub fn register<T>(&self, diagnostic: T)
where
T: Diagnostic + 'static + Sync + Send,
{
self.register_inner(Arc::new(diagnostic));
}
fn register_inner(&self, diagnostic: Arc<dyn Diagnostic + Sync + Send>) {
let type_ = diagnostic.type_();
assert!(
TYPE_PATTERN.is_match(type_),
"{type_} must be `lower.case.dot.delimited.v1`",
);
match self.diagnostics.lock().entry(type_.to_string()) {
Entry::Occupied(_) => {
panic!("a diagnostic has already been registered for type {type_}")
}
Entry::Vacant(e) => {
e.insert(diagnostic);
}
}
}
pub fn get(&self, type_: &str) -> Option<Arc<dyn Diagnostic + Sync + Send>> {
self.diagnostics.lock().get(type_).cloned()
}
}