1use std::ffi::CStr;
7use std::os::raw::c_char;
8use std::ptr;
9use std::sync::Arc;
10
11use super::HddsError;
12
13#[repr(C)]
15pub struct HddsMetrics {
16 _private: [u8; 0],
17}
18
19#[repr(C)]
21pub struct HddsTelemetryExporter {
22 _private: [u8; 0],
23}
24
25#[repr(C)]
27#[derive(Debug, Clone, Copy, Default)]
28pub struct HddsMetricsSnapshot {
29 pub timestamp_ns: u64,
31 pub messages_sent: u64,
33 pub messages_received: u64,
35 pub messages_dropped: u64,
37 pub bytes_sent: u64,
39 pub latency_p50_ns: u64,
41 pub latency_p99_ns: u64,
43 pub latency_p999_ns: u64,
45 pub merge_full_count: u64,
47 pub would_block_count: u64,
49}
50
51#[no_mangle]
66pub unsafe extern "C" fn hdds_telemetry_init() -> *mut HddsMetrics {
67 let metrics = hdds::telemetry::init_metrics();
68 Arc::into_raw(metrics) as *mut HddsMetrics
69}
70
71#[no_mangle]
79pub unsafe extern "C" fn hdds_telemetry_get() -> *mut HddsMetrics {
80 match hdds::telemetry::get_metrics_opt() {
81 Some(metrics) => Arc::into_raw(metrics) as *mut HddsMetrics,
82 None => ptr::null_mut(),
83 }
84}
85
86#[no_mangle]
91pub unsafe extern "C" fn hdds_telemetry_release(metrics: *mut HddsMetrics) {
92 if !metrics.is_null() {
93 let _ = Arc::from_raw(metrics.cast::<hdds::telemetry::MetricsCollector>());
94 }
95}
96
97#[no_mangle]
106pub unsafe extern "C" fn hdds_telemetry_snapshot(
107 metrics: *mut HddsMetrics,
108 out: *mut HddsMetricsSnapshot,
109) -> HddsError {
110 if metrics.is_null() || out.is_null() {
111 return HddsError::HddsInvalidArgument;
112 }
113
114 let arc = Arc::from_raw(metrics.cast::<hdds::telemetry::MetricsCollector>());
116 let clone = arc.clone();
117 let _ = Arc::into_raw(arc); let frame = clone.snapshot();
120
121 let mut snapshot = HddsMetricsSnapshot {
123 timestamp_ns: frame.ts_ns,
124 ..Default::default()
125 };
126
127 use hdds::telemetry::metrics::*;
128 for field in &frame.fields {
129 match field.tag {
130 TAG_MESSAGES_SENT => snapshot.messages_sent = field.value_u64,
131 TAG_MESSAGES_RECEIVED => snapshot.messages_received = field.value_u64,
132 TAG_MESSAGES_DROPPED => snapshot.messages_dropped = field.value_u64,
133 TAG_BYTES_SENT => snapshot.bytes_sent = field.value_u64,
134 TAG_LATENCY_P50 => snapshot.latency_p50_ns = field.value_u64,
135 TAG_LATENCY_P99 => snapshot.latency_p99_ns = field.value_u64,
136 TAG_LATENCY_P999 => snapshot.latency_p999_ns = field.value_u64,
137 TAG_MERGE_FULL_COUNT => snapshot.merge_full_count = field.value_u64,
138 TAG_WOULD_BLOCK_COUNT => snapshot.would_block_count = field.value_u64,
139 _ => {}
140 }
141 }
142
143 *out = snapshot;
144 HddsError::HddsOk
145}
146
147#[no_mangle]
156pub unsafe extern "C" fn hdds_telemetry_record_latency(
157 metrics: *mut HddsMetrics,
158 start_ns: u64,
159 end_ns: u64,
160) {
161 if metrics.is_null() {
162 return;
163 }
164
165 let arc = Arc::from_raw(metrics.cast::<hdds::telemetry::MetricsCollector>());
166 arc.add_latency_sample(start_ns, end_ns);
167 let _ = Arc::into_raw(arc);
168}
169
170#[no_mangle]
189pub unsafe extern "C" fn hdds_telemetry_start_exporter(
190 bind_addr: *const c_char,
191 port: u16,
192) -> *mut HddsTelemetryExporter {
193 if bind_addr.is_null() {
194 return ptr::null_mut();
195 }
196
197 let Ok(addr_str) = CStr::from_ptr(bind_addr).to_str() else {
198 return ptr::null_mut();
199 };
200
201 match hdds::telemetry::init_exporter(addr_str, port) {
202 Ok(exporter) => Arc::into_raw(exporter) as *mut HddsTelemetryExporter,
203 Err(e) => {
204 log::error!("Failed to start telemetry exporter: {}", e);
205 ptr::null_mut()
206 }
207 }
208}
209
210#[no_mangle]
215pub unsafe extern "C" fn hdds_telemetry_stop_exporter(exporter: *mut HddsTelemetryExporter) {
216 if !exporter.is_null() {
217 let _ = Arc::from_raw(exporter.cast::<hdds::telemetry::Exporter>());
218 }
219}