use crate::metrics::{ChannelMetrics, MetricsSnapshot};
use pyo3::prelude::*;
use std::sync::Arc;
use std::time::Duration;
#[pyclass(name = "ChannelMetrics")]
pub struct PyChannelMetrics {
inner: Arc<ChannelMetrics>,
}
#[pymethods]
impl PyChannelMetrics {
#[new]
fn new() -> Self {
Self {
inner: Arc::new(ChannelMetrics::new()),
}
}
fn record_send(&self, bytes: usize) {
self.inner.record_send(bytes);
}
fn record_recv(&self, bytes: usize) {
self.inner.record_recv(bytes);
}
fn record_send_error(&self) {
self.inner.record_send_error();
}
fn record_recv_error(&self) {
self.inner.record_recv_error();
}
fn record_latency_us(&self, latency_us: u64) {
self.inner.record_latency(Duration::from_micros(latency_us));
}
fn record_latency_ms(&self, latency_ms: u64) {
self.inner.record_latency(Duration::from_millis(latency_ms));
}
fn set_queue_depth(&self, depth: u64) {
self.inner.set_queue_depth(depth);
}
#[getter]
fn messages_sent(&self) -> u64 {
self.inner.messages_sent()
}
#[getter]
fn messages_received(&self) -> u64 {
self.inner.messages_received()
}
#[getter]
fn bytes_sent(&self) -> u64 {
self.inner.bytes_sent()
}
#[getter]
fn bytes_received(&self) -> u64 {
self.inner.bytes_received()
}
#[getter]
fn send_errors(&self) -> u64 {
self.inner.send_errors()
}
#[getter]
fn receive_errors(&self) -> u64 {
self.inner.receive_errors()
}
#[getter]
fn queue_depth(&self) -> u64 {
self.inner.queue_depth()
}
#[getter]
fn peak_queue_depth(&self) -> u64 {
self.inner.peak_queue_depth()
}
#[getter]
fn avg_latency_us(&self) -> u64 {
self.inner.avg_latency_us()
}
#[getter]
fn min_latency_us(&self) -> Option<u64> {
self.inner.min_latency_us()
}
#[getter]
fn max_latency_us(&self) -> u64 {
self.inner.max_latency_us()
}
fn latency_percentile(&self, percentile: u8) -> u64 {
self.inner.latency_percentile(percentile)
}
#[getter]
fn elapsed_secs(&self) -> f64 {
self.inner.elapsed().as_secs_f64()
}
#[getter]
fn send_throughput(&self) -> f64 {
self.inner.send_throughput()
}
#[getter]
fn recv_throughput(&self) -> f64 {
self.inner.recv_throughput()
}
#[getter]
fn send_bandwidth(&self) -> f64 {
self.inner.send_bandwidth()
}
#[getter]
fn recv_bandwidth(&self) -> f64 {
self.inner.recv_bandwidth()
}
fn reset(&self) {
self.inner.reset();
}
fn snapshot(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
let snapshot = self.inner.snapshot();
snapshot_to_dict(py, &snapshot)
}
fn to_json(&self) -> String {
self.inner.to_json()
}
fn to_json_pretty(&self) -> String {
self.inner.to_json_pretty()
}
fn to_prometheus(&self, prefix: &str) -> String {
self.inner.to_prometheus(prefix)
}
fn __repr__(&self) -> String {
format!(
"ChannelMetrics(sent={}, recv={}, bytes_sent={}, bytes_recv={}, avg_latency={}µs)",
self.inner.messages_sent(),
self.inner.messages_received(),
self.inner.bytes_sent(),
self.inner.bytes_received(),
self.inner.avg_latency_us()
)
}
}
#[pyclass(name = "MetricsSnapshot")]
#[derive(Clone)]
pub struct PyMetricsSnapshot {
inner: MetricsSnapshot,
}
#[pymethods]
impl PyMetricsSnapshot {
#[getter]
fn messages_sent(&self) -> u64 {
self.inner.messages_sent
}
#[getter]
fn messages_received(&self) -> u64 {
self.inner.messages_received
}
#[getter]
fn bytes_sent(&self) -> u64 {
self.inner.bytes_sent
}
#[getter]
fn bytes_received(&self) -> u64 {
self.inner.bytes_received
}
#[getter]
fn send_errors(&self) -> u64 {
self.inner.send_errors
}
#[getter]
fn receive_errors(&self) -> u64 {
self.inner.receive_errors
}
#[getter]
fn queue_depth(&self) -> u64 {
self.inner.queue_depth
}
#[getter]
fn peak_queue_depth(&self) -> u64 {
self.inner.peak_queue_depth
}
#[getter]
fn avg_latency_us(&self) -> u64 {
self.inner.avg_latency_us
}
#[getter]
fn min_latency_us(&self) -> Option<u64> {
self.inner.min_latency_us
}
#[getter]
fn max_latency_us(&self) -> u64 {
self.inner.max_latency_us
}
#[getter]
fn p50_latency_us(&self) -> u64 {
self.inner.p50_latency_us
}
#[getter]
fn p95_latency_us(&self) -> u64 {
self.inner.p95_latency_us
}
#[getter]
fn p99_latency_us(&self) -> u64 {
self.inner.p99_latency_us
}
#[getter]
fn elapsed_secs(&self) -> f64 {
self.inner.elapsed_secs
}
#[getter]
fn send_throughput(&self) -> f64 {
self.inner.send_throughput
}
#[getter]
fn recv_throughput(&self) -> f64 {
self.inner.recv_throughput
}
#[getter]
fn send_bandwidth(&self) -> f64 {
self.inner.send_bandwidth
}
#[getter]
fn recv_bandwidth(&self) -> f64 {
self.inner.recv_bandwidth
}
fn to_dict(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
snapshot_to_dict(py, &self.inner)
}
fn __repr__(&self) -> String {
format!(
"MetricsSnapshot(sent={}, recv={}, avg_latency={}µs, p99={}µs)",
self.inner.messages_sent,
self.inner.messages_received,
self.inner.avg_latency_us,
self.inner.p99_latency_us
)
}
}
fn snapshot_to_dict(py: Python<'_>, snapshot: &MetricsSnapshot) -> PyResult<Py<PyAny>> {
use pyo3::types::PyDict;
let dict = PyDict::new(py);
dict.set_item("messages_sent", snapshot.messages_sent)?;
dict.set_item("messages_received", snapshot.messages_received)?;
dict.set_item("bytes_sent", snapshot.bytes_sent)?;
dict.set_item("bytes_received", snapshot.bytes_received)?;
dict.set_item("send_errors", snapshot.send_errors)?;
dict.set_item("receive_errors", snapshot.receive_errors)?;
dict.set_item("queue_depth", snapshot.queue_depth)?;
dict.set_item("peak_queue_depth", snapshot.peak_queue_depth)?;
dict.set_item("avg_latency_us", snapshot.avg_latency_us)?;
dict.set_item("min_latency_us", snapshot.min_latency_us)?;
dict.set_item("max_latency_us", snapshot.max_latency_us)?;
dict.set_item("p50_latency_us", snapshot.p50_latency_us)?;
dict.set_item("p95_latency_us", snapshot.p95_latency_us)?;
dict.set_item("p99_latency_us", snapshot.p99_latency_us)?;
dict.set_item("elapsed_secs", snapshot.elapsed_secs)?;
dict.set_item("send_throughput", snapshot.send_throughput)?;
dict.set_item("recv_throughput", snapshot.recv_throughput)?;
dict.set_item("send_bandwidth", snapshot.send_bandwidth)?;
dict.set_item("recv_bandwidth", snapshot.recv_bandwidth)?;
Ok(dict.into())
}