use crate::error::Result;
use opentelemetry::KeyValue;
use opentelemetry::metrics::{Counter, Histogram, Meter};
pub struct IoMetrics {
pub file_open_count: Counter<u64>,
pub file_open_duration: Histogram<f64>,
pub file_close_count: Counter<u64>,
pub file_read_count: Counter<u64>,
pub file_read_duration: Histogram<f64>,
pub file_read_bytes: Counter<u64>,
pub file_write_count: Counter<u64>,
pub file_write_duration: Histogram<f64>,
pub file_write_bytes: Counter<u64>,
pub network_request_count: Counter<u64>,
pub network_request_duration: Histogram<f64>,
pub network_bytes_sent: Counter<u64>,
pub network_bytes_received: Counter<u64>,
pub network_errors: Counter<u64>,
pub cloud_get_count: Counter<u64>,
pub cloud_get_duration: Histogram<f64>,
pub cloud_put_count: Counter<u64>,
pub cloud_put_duration: Histogram<f64>,
pub cloud_list_count: Counter<u64>,
pub cloud_list_duration: Histogram<f64>,
pub read_throughput_mbps: Histogram<f64>,
pub write_throughput_mbps: Histogram<f64>,
pub read_latency_ms: Histogram<f64>,
pub write_latency_ms: Histogram<f64>,
}
impl IoMetrics {
pub fn new(meter: Meter) -> Result<Self> {
Ok(Self {
file_open_count: meter
.u64_counter("oxigdal.io.file.open.count")
.with_description("Number of file open operations")
.build(),
file_open_duration: meter
.f64_histogram("oxigdal.io.file.open.duration")
.with_description("Duration of file open operations in milliseconds")
.build(),
file_close_count: meter
.u64_counter("oxigdal.io.file.close.count")
.with_description("Number of file close operations")
.build(),
file_read_count: meter
.u64_counter("oxigdal.io.file.read.count")
.with_description("Number of file read operations")
.build(),
file_read_duration: meter
.f64_histogram("oxigdal.io.file.read.duration")
.with_description("Duration of file read operations in milliseconds")
.build(),
file_read_bytes: meter
.u64_counter("oxigdal.io.file.read.bytes")
.with_description("Bytes read from files")
.build(),
file_write_count: meter
.u64_counter("oxigdal.io.file.write.count")
.with_description("Number of file write operations")
.build(),
file_write_duration: meter
.f64_histogram("oxigdal.io.file.write.duration")
.with_description("Duration of file write operations in milliseconds")
.build(),
file_write_bytes: meter
.u64_counter("oxigdal.io.file.write.bytes")
.with_description("Bytes written to files")
.build(),
network_request_count: meter
.u64_counter("oxigdal.io.network.request.count")
.with_description("Number of network requests")
.build(),
network_request_duration: meter
.f64_histogram("oxigdal.io.network.request.duration")
.with_description("Duration of network requests in milliseconds")
.build(),
network_bytes_sent: meter
.u64_counter("oxigdal.io.network.bytes.sent")
.with_description("Bytes sent over network")
.build(),
network_bytes_received: meter
.u64_counter("oxigdal.io.network.bytes.received")
.with_description("Bytes received from network")
.build(),
network_errors: meter
.u64_counter("oxigdal.io.network.errors")
.with_description("Number of network errors")
.build(),
cloud_get_count: meter
.u64_counter("oxigdal.io.cloud.get.count")
.with_description("Number of cloud storage GET operations")
.build(),
cloud_get_duration: meter
.f64_histogram("oxigdal.io.cloud.get.duration")
.with_description("Duration of cloud storage GET in milliseconds")
.build(),
cloud_put_count: meter
.u64_counter("oxigdal.io.cloud.put.count")
.with_description("Number of cloud storage PUT operations")
.build(),
cloud_put_duration: meter
.f64_histogram("oxigdal.io.cloud.put.duration")
.with_description("Duration of cloud storage PUT in milliseconds")
.build(),
cloud_list_count: meter
.u64_counter("oxigdal.io.cloud.list.count")
.with_description("Number of cloud storage LIST operations")
.build(),
cloud_list_duration: meter
.f64_histogram("oxigdal.io.cloud.list.duration")
.with_description("Duration of cloud storage LIST in milliseconds")
.build(),
read_throughput_mbps: meter
.f64_histogram("oxigdal.io.read.throughput.mbps")
.with_description("Read throughput in MB/s")
.build(),
write_throughput_mbps: meter
.f64_histogram("oxigdal.io.write.throughput.mbps")
.with_description("Write throughput in MB/s")
.build(),
read_latency_ms: meter
.f64_histogram("oxigdal.io.read.latency.ms")
.with_description("Read latency in milliseconds")
.build(),
write_latency_ms: meter
.f64_histogram("oxigdal.io.write.latency.ms")
.with_description("Write latency in milliseconds")
.build(),
})
}
pub fn record_file_read(&self, duration_ms: f64, bytes: u64, path: &str, success: bool) {
let attrs = vec![
KeyValue::new("path", path.to_string()),
KeyValue::new("success", success),
];
self.file_read_count.add(1, &attrs);
self.file_read_duration.record(duration_ms, &attrs);
if success {
self.file_read_bytes.add(bytes, &attrs);
if duration_ms > 0.0 {
let throughput_mbps = (bytes as f64 / (1024.0 * 1024.0)) / (duration_ms / 1000.0);
self.read_throughput_mbps.record(throughput_mbps, &attrs);
}
}
}
pub fn record_file_write(&self, duration_ms: f64, bytes: u64, path: &str, success: bool) {
let attrs = vec![
KeyValue::new("path", path.to_string()),
KeyValue::new("success", success),
];
self.file_write_count.add(1, &attrs);
self.file_write_duration.record(duration_ms, &attrs);
if success {
self.file_write_bytes.add(bytes, &attrs);
if duration_ms > 0.0 {
let throughput_mbps = (bytes as f64 / (1024.0 * 1024.0)) / (duration_ms / 1000.0);
self.write_throughput_mbps.record(throughput_mbps, &attrs);
}
}
}
pub fn record_network_request(
&self,
duration_ms: f64,
bytes_sent: u64,
bytes_received: u64,
method: &str,
success: bool,
) {
let attrs = vec![
KeyValue::new("method", method.to_string()),
KeyValue::new("success", success),
];
self.network_request_count.add(1, &attrs);
self.network_request_duration.record(duration_ms, &attrs);
self.network_bytes_sent.add(bytes_sent, &attrs);
self.network_bytes_received.add(bytes_received, &attrs);
if !success {
self.network_errors.add(1, &attrs);
}
}
pub fn record_cloud_get(&self, duration_ms: f64, provider: &str, success: bool) {
let attrs = vec![
KeyValue::new("provider", provider.to_string()),
KeyValue::new("success", success),
];
self.cloud_get_count.add(1, &attrs);
self.cloud_get_duration.record(duration_ms, &attrs);
}
pub fn record_cloud_put(&self, duration_ms: f64, provider: &str, success: bool) {
let attrs = vec![
KeyValue::new("provider", provider.to_string()),
KeyValue::new("success", success),
];
self.cloud_put_count.add(1, &attrs);
self.cloud_put_duration.record(duration_ms, &attrs);
}
}
#[cfg(test)]
mod tests {
use super::*;
use opentelemetry::global;
#[test]
fn test_io_metrics_creation() {
let meter = global::meter("test");
let metrics = IoMetrics::new(meter);
assert!(metrics.is_ok());
}
}