extern crate alloc;
mod export;
mod metrics;
mod types;
pub mod zpl_collector;
pub use export::*;
pub use metrics::*;
pub use types::*;
use alloc::string::String;
use alloc::vec::Vec;
use spin::Mutex;
static METRICS_REGISTRY: Mutex<Option<MetricsRegistry>> = Mutex::new(None);
pub fn init() {
let mut registry = METRICS_REGISTRY.lock();
if registry.is_none() {
*registry = Some(MetricsRegistry::new());
}
}
pub struct Telemetry;
impl Telemetry {
pub fn register_counter(
name: &str,
help: &str,
labels: &[&str],
) -> Result<MetricId, TelemetryError> {
let mut registry = METRICS_REGISTRY.lock();
let registry = registry.as_mut().ok_or(TelemetryError::NotInitialized)?;
registry.register_counter(name, help, labels)
}
pub fn register_gauge(
name: &str,
help: &str,
labels: &[&str],
) -> Result<MetricId, TelemetryError> {
let mut registry = METRICS_REGISTRY.lock();
let registry = registry.as_mut().ok_or(TelemetryError::NotInitialized)?;
registry.register_gauge(name, help, labels)
}
pub fn register_histogram(
name: &str,
help: &str,
labels: &[&str],
buckets: &[f64],
) -> Result<MetricId, TelemetryError> {
let mut registry = METRICS_REGISTRY.lock();
let registry = registry.as_mut().ok_or(TelemetryError::NotInitialized)?;
registry.register_histogram(name, help, labels, buckets)
}
pub fn counter_inc(id: MetricId, labels: &[&str]) {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.counter_inc(id, labels, 1.0);
}
}
pub fn counter_add(id: MetricId, labels: &[&str], value: f64) {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.counter_inc(id, labels, value);
}
}
pub fn gauge_set(id: MetricId, labels: &[&str], value: f64) {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.gauge_set(id, labels, value);
}
}
pub fn gauge_inc(id: MetricId, labels: &[&str]) {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.gauge_add(id, labels, 1.0);
}
}
pub fn gauge_dec(id: MetricId, labels: &[&str]) {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.gauge_add(id, labels, -1.0);
}
}
pub fn histogram_observe(id: MetricId, labels: &[&str], value: f64) {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.histogram_observe(id, labels, value);
}
}
pub fn export_prometheus() -> Result<String, TelemetryError> {
let registry = METRICS_REGISTRY.lock();
let registry = registry.as_ref().ok_or(TelemetryError::NotInitialized)?;
Ok(export_prometheus_format(registry))
}
pub fn export_json() -> Result<String, TelemetryError> {
let registry = METRICS_REGISTRY.lock();
let registry = registry.as_ref().ok_or(TelemetryError::NotInitialized)?;
Ok(export_json_format(registry))
}
pub fn list_metrics() -> Result<Vec<MetricInfo>, TelemetryError> {
let registry = METRICS_REGISTRY.lock();
let registry = registry.as_ref().ok_or(TelemetryError::NotInitialized)?;
Ok(registry.list_metrics())
}
pub fn reset() {
if let Some(ref mut registry) = *METRICS_REGISTRY.lock() {
registry.reset();
}
}
pub fn collect_standard_metrics(dataset: &str) {
collect_filesystem_metrics(dataset);
}
}
pub mod builtin {
use super::*;
pub fn init_builtin_metrics() -> Result<BuiltinMetrics, TelemetryError> {
let read_ops = Telemetry::register_counter(
"lcpfs_read_ops_total",
"Total number of read operations",
&["dataset"],
)?;
let write_ops = Telemetry::register_counter(
"lcpfs_write_ops_total",
"Total number of write operations",
&["dataset"],
)?;
let read_bytes = Telemetry::register_counter(
"lcpfs_read_bytes_total",
"Total bytes read",
&["dataset"],
)?;
let write_bytes = Telemetry::register_counter(
"lcpfs_write_bytes_total",
"Total bytes written",
&["dataset"],
)?;
let used_bytes = Telemetry::register_gauge(
"lcpfs_used_bytes",
"Used storage space in bytes",
&["dataset"],
)?;
let free_bytes = Telemetry::register_gauge(
"lcpfs_free_bytes",
"Free storage space in bytes",
&["dataset"],
)?;
let file_count =
Telemetry::register_gauge("lcpfs_file_count", "Number of files", &["dataset"])?;
let read_latency = Telemetry::register_histogram(
"lcpfs_read_latency_seconds",
"Read operation latency in seconds",
&["dataset"],
&[0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0],
)?;
let write_latency = Telemetry::register_histogram(
"lcpfs_write_latency_seconds",
"Write operation latency in seconds",
&["dataset"],
&[0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0],
)?;
Ok(BuiltinMetrics {
read_ops,
write_ops,
read_bytes,
write_bytes,
used_bytes,
free_bytes,
file_count,
read_latency,
write_latency,
})
}
#[derive(Debug, Clone)]
pub struct BuiltinMetrics {
pub read_ops: MetricId,
pub write_ops: MetricId,
pub read_bytes: MetricId,
pub write_bytes: MetricId,
pub used_bytes: MetricId,
pub free_bytes: MetricId,
pub file_count: MetricId,
pub read_latency: MetricId,
pub write_latency: MetricId,
}
}
fn collect_filesystem_metrics(dataset: &str) {
zpl_collector::collect_all_metrics(dataset);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_init() {
init();
let registry = METRICS_REGISTRY.lock();
assert!(registry.is_some());
}
}