use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr;
use std::sync::Arc;
use super::HddsError;
#[repr(C)]
pub struct HddsMetrics {
_private: [u8; 0],
}
#[repr(C)]
pub struct HddsTelemetryExporter {
_private: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct HddsMetricsSnapshot {
pub timestamp_ns: u64,
pub messages_sent: u64,
pub messages_received: u64,
pub messages_dropped: u64,
pub bytes_sent: u64,
pub latency_p50_ns: u64,
pub latency_p99_ns: u64,
pub latency_p999_ns: u64,
pub merge_full_count: u64,
pub would_block_count: u64,
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_init() -> *mut HddsMetrics {
let metrics = hdds::telemetry::init_metrics();
Arc::into_raw(metrics) as *mut HddsMetrics
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_get() -> *mut HddsMetrics {
match hdds::telemetry::get_metrics_opt() {
Some(metrics) => Arc::into_raw(metrics) as *mut HddsMetrics,
None => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_release(metrics: *mut HddsMetrics) {
if !metrics.is_null() {
let _ = Arc::from_raw(metrics.cast::<hdds::telemetry::MetricsCollector>());
}
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_snapshot(
metrics: *mut HddsMetrics,
out: *mut HddsMetricsSnapshot,
) -> HddsError {
if metrics.is_null() || out.is_null() {
return HddsError::HddsInvalidArgument;
}
let arc = Arc::from_raw(metrics.cast::<hdds::telemetry::MetricsCollector>());
let clone = arc.clone();
let _ = Arc::into_raw(arc);
let frame = clone.snapshot();
let mut snapshot = HddsMetricsSnapshot {
timestamp_ns: frame.ts_ns,
..Default::default()
};
use hdds::telemetry::metrics::*;
for field in &frame.fields {
match field.tag {
TAG_MESSAGES_SENT => snapshot.messages_sent = field.value_u64,
TAG_MESSAGES_RECEIVED => snapshot.messages_received = field.value_u64,
TAG_MESSAGES_DROPPED => snapshot.messages_dropped = field.value_u64,
TAG_BYTES_SENT => snapshot.bytes_sent = field.value_u64,
TAG_LATENCY_P50 => snapshot.latency_p50_ns = field.value_u64,
TAG_LATENCY_P99 => snapshot.latency_p99_ns = field.value_u64,
TAG_LATENCY_P999 => snapshot.latency_p999_ns = field.value_u64,
TAG_MERGE_FULL_COUNT => snapshot.merge_full_count = field.value_u64,
TAG_WOULD_BLOCK_COUNT => snapshot.would_block_count = field.value_u64,
_ => {}
}
}
*out = snapshot;
HddsError::HddsOk
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_record_latency(
metrics: *mut HddsMetrics,
start_ns: u64,
end_ns: u64,
) {
if metrics.is_null() {
return;
}
let arc = Arc::from_raw(metrics.cast::<hdds::telemetry::MetricsCollector>());
arc.add_latency_sample(start_ns, end_ns);
let _ = Arc::into_raw(arc);
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_start_exporter(
bind_addr: *const c_char,
port: u16,
) -> *mut HddsTelemetryExporter {
if bind_addr.is_null() {
return ptr::null_mut();
}
let Ok(addr_str) = CStr::from_ptr(bind_addr).to_str() else {
return ptr::null_mut();
};
match hdds::telemetry::init_exporter(addr_str, port) {
Ok(exporter) => Arc::into_raw(exporter) as *mut HddsTelemetryExporter,
Err(e) => {
log::error!("Failed to start telemetry exporter: {}", e);
ptr::null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn hdds_telemetry_stop_exporter(exporter: *mut HddsTelemetryExporter) {
if !exporter.is_null() {
let _ = Arc::from_raw(exporter.cast::<hdds::telemetry::Exporter>());
}
}