Skip to main content

ri/java/classes/
observability.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Observability Module JNI Bindings
19//!
20//! JNI bindings for Ri observability classes.
21
22use jni::JNIEnv;
23use jni::objects::{JClass, JObject, JString, JDoubleArray, JValue};
24use jni::sys::{jdouble, jint, jlong, jstring, jobjectArray, jobject};
25use crate::observability::{
26    RiObservabilityModule, RiObservabilityConfig, RiTracer, RiSpanKind, RiSpanStatus,
27    RiMetric, RiMetricConfig, RiMetricType, RiMetricsRegistry,
28};
29#[cfg(feature = "system_info")]
30use crate::observability::{
31    RiSystemMetricsCollector, RiSystemMetrics, RiCPUMetrics, RiMemoryMetrics, RiDiskMetrics, RiNetworkMetrics,
32};
33use crate::java::exception::check_not_null;
34
35#[no_mangle]
36pub extern "system" fn Java_com_dunimd_ri_observability_RiObservabilityConfig_new0(
37    _env: JNIEnv,
38    _class: JClass,
39) -> jlong {
40    let config = Box::new(RiObservabilityConfig::default());
41    Box::into_raw(config) as jlong
42}
43
44#[no_mangle]
45pub extern "system" fn Java_com_dunimd_ri_observability_RiObservabilityConfig_free0(
46    _env: JNIEnv,
47    _class: JClass,
48    ptr: jlong,
49) {
50    if ptr != 0 {
51        unsafe {
52            let _ = Box::from_raw(ptr as *mut RiObservabilityConfig);
53        }
54    }
55}
56
57#[no_mangle]
58pub extern "system" fn Java_com_dunimd_ri_observability_RiObservabilityModule_new0(
59    mut env: JNIEnv,
60    _class: JClass,
61    config_ptr: jlong,
62) -> jlong {
63    if !check_not_null(&mut env, config_ptr, "RiObservabilityConfig") {
64        return 0;
65    }
66    let module = Box::new(RiObservabilityModule::new());
67    Box::into_raw(module) as jlong
68}
69
70#[no_mangle]
71pub extern "system" fn Java_com_dunimd_ri_observability_RiObservabilityModule_free0(
72    _env: JNIEnv,
73    _class: JClass,
74    ptr: jlong,
75) {
76    if ptr != 0 {
77        unsafe {
78            let _ = Box::from_raw(ptr as *mut RiObservabilityModule);
79        }
80    }
81}
82
83// RiTracer JNI bindings
84#[no_mangle]
85pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_new0(
86    _env: JNIEnv,
87    _class: JClass,
88    sampling_rate: jdouble,
89) -> jlong {
90    let tracer = Box::new(RiTracer::new(sampling_rate));
91    Box::into_raw(tracer) as jlong
92}
93
94#[no_mangle]
95pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_startTrace0(
96    mut env: JNIEnv,
97    _class: JClass,
98    ptr: jlong,
99    name: JString,
100) -> jstring {
101    if ptr == 0 {
102        return std::ptr::null_mut();
103    }
104    
105    let tracer = unsafe { &*(ptr as *const RiTracer) };
106    let name_str: String = match env.get_string(&name) {
107        Ok(s) => s.into(),
108        Err(_) => return std::ptr::null_mut(),
109    };
110    
111    match tracer.start_trace(name_str) {
112        Some(trace_id) => {
113            match env.new_string(trace_id.as_str()) {
114                Ok(s) => s.into_raw(),
115                Err(_) => std::ptr::null_mut(),
116            }
117        }
118        None => std::ptr::null_mut(),
119    }
120}
121
122#[no_mangle]
123pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_span0(
124    mut env: JNIEnv,
125    _class: JClass,
126    ptr: jlong,
127    name: JString,
128    kind: JString,
129) -> jstring {
130    if ptr == 0 {
131        return std::ptr::null_mut();
132    }
133    
134    let tracer = unsafe { &*(ptr as *const RiTracer) };
135    let name_str: String = match env.get_string(&name) {
136        Ok(s) => s.into(),
137        Err(_) => return std::ptr::null_mut(),
138    };
139    let kind_str: String = match env.get_string(&kind) {
140        Ok(s) => s.into(),
141        Err(_) => return std::ptr::null_mut(),
142    };
143    
144    let span_kind = match kind_str.as_str() {
145        "Server" => RiSpanKind::Server,
146        "Client" => RiSpanKind::Client,
147        "Producer" => RiSpanKind::Producer,
148        "Consumer" => RiSpanKind::Consumer,
149        _ => RiSpanKind::Internal,
150    };
151    
152    match tracer.start_span_from_context(name_str, span_kind) {
153        Some(span_id) => {
154            match env.new_string(span_id.as_str()) {
155                Ok(s) => s.into_raw(),
156                Err(_) => std::ptr::null_mut(),
157            }
158        }
159        None => std::ptr::null_mut(),
160    }
161}
162
163#[no_mangle]
164pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_finishSpan0(
165    mut env: JNIEnv,
166    _class: JClass,
167    ptr: jlong,
168    span_id: JString,
169    status: JString,
170) {
171    if ptr == 0 {
172        return;
173    }
174    
175    let tracer = unsafe { &*(ptr as *const RiTracer) };
176    let span_id_str: String = match env.get_string(&span_id) {
177        Ok(s) => s.into(),
178        Err(_) => return,
179    };
180    let status_str: String = match env.get_string(&status) {
181        Ok(s) => s.into(),
182        Err(_) => return,
183    };
184    
185    let span_status = match status_str.as_str() {
186        "Ok" => RiSpanStatus::Ok,
187        "Error" => RiSpanStatus::Error("Java error".to_string()),
188        _ => RiSpanStatus::Unset,
189    };
190    
191    use crate::observability::tracing::RiSpanId;
192    let span_id_obj = RiSpanId::from_string(span_id_str);
193    let _ = tracer.end_span(&span_id_obj, span_status);
194}
195
196#[no_mangle]
197pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_setAttribute0(
198    mut env: JNIEnv,
199    _class: JClass,
200    ptr: jlong,
201    span_id: JString,
202    key: JString,
203    value: JString,
204) {
205    if ptr == 0 {
206        return;
207    }
208    
209    let tracer = unsafe { &*(ptr as *const RiTracer) };
210    let span_id_str: String = match env.get_string(&span_id) {
211        Ok(s) => s.into(),
212        Err(_) => return,
213    };
214    let key_str: String = match env.get_string(&key) {
215        Ok(s) => s.into(),
216        Err(_) => return,
217    };
218    let value_str: String = match env.get_string(&value) {
219        Ok(s) => s.into(),
220        Err(_) => return,
221    };
222    
223    use crate::observability::tracing::RiSpanId;
224    let span_id_obj = RiSpanId::from_string(span_id_str);
225    let _ = tracer.span_mut(&span_id_obj, |span| {
226        span.set_attribute(key_str, value_str);
227    });
228}
229
230#[no_mangle]
231pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_addEvent0(
232    mut env: JNIEnv,
233    _class: JClass,
234    ptr: jlong,
235    span_id: JString,
236    name: JString,
237) {
238    if ptr == 0 {
239        return;
240    }
241    
242    let tracer = unsafe { &*(ptr as *const RiTracer) };
243    let span_id_str: String = match env.get_string(&span_id) {
244        Ok(s) => s.into(),
245        Err(_) => return,
246    };
247    let name_str: String = match env.get_string(&name) {
248        Ok(s) => s.into(),
249        Err(_) => return,
250    };
251    
252    use crate::observability::tracing::RiSpanId;
253    let span_id_obj = RiSpanId::from_string(span_id_str);
254    let _ = tracer.span_mut(&span_id_obj, |span| {
255        span.add_event(name_str, std::collections::HashMap::default());
256    });
257}
258
259#[no_mangle]
260pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_getActiveTraceCount0(
261    _env: JNIEnv,
262    _class: JClass,
263    ptr: jlong,
264) -> jint {
265    if ptr == 0 {
266        return 0;
267    }
268    
269    let tracer = unsafe { &*(ptr as *const RiTracer) };
270    tracer.active_trace_count() as jint
271}
272
273#[no_mangle]
274pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_getActiveSpanCount0(
275    _env: JNIEnv,
276    _class: JClass,
277    ptr: jlong,
278) -> jint {
279    if ptr == 0 {
280        return 0;
281    }
282    
283    let tracer = unsafe { &*(ptr as *const RiTracer) };
284    tracer.active_span_count() as jint
285}
286
287#[no_mangle]
288pub extern "system" fn Java_com_dunimd_ri_observability_RiTracer_free0(
289    _env: JNIEnv,
290    _class: JClass,
291    ptr: jlong,
292) {
293    if ptr != 0 {
294        unsafe {
295            let _ = Box::from_raw(ptr as *mut RiTracer);
296        }
297    }
298}
299
300// RiMetricConfig JNI bindings
301#[no_mangle]
302pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricConfig_new0(
303    mut env: JNIEnv,
304    _class: JClass,
305    name: JString,
306    metric_type: jint,
307) -> jlong {
308    let name_str: String = match env.get_string(&name) {
309        Ok(s) => s.into(),
310        Err(_) => return 0,
311    };
312    
313    let metric_type_enum = match metric_type {
314        0 => RiMetricType::Counter,
315        1 => RiMetricType::Gauge,
316        2 => RiMetricType::Histogram,
317        3 => RiMetricType::Summary,
318        _ => RiMetricType::Counter,
319    };
320    
321    let config = Box::new(RiMetricConfig {
322        metric_type: metric_type_enum,
323        name: name_str,
324        help: String::new(),
325        buckets: vec![0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
326        quantiles: vec![0.5, 0.9, 0.95, 0.99],
327        max_age: std::time::Duration::from_secs(600),
328        age_buckets: 5,
329    });
330    
331    Box::into_raw(config) as jlong
332}
333
334#[no_mangle]
335pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricConfig_setHelp0(
336    mut env: JNIEnv,
337    _class: JClass,
338    ptr: jlong,
339    help: JString,
340) {
341    if ptr == 0 {
342        return;
343    }
344    
345    let help_str: String = match env.get_string(&help) {
346        Ok(s) => s.into(),
347        Err(_) => return,
348    };
349    
350    let config = unsafe { &mut *(ptr as *mut RiMetricConfig) };
351    config.help = help_str;
352}
353
354#[no_mangle]
355pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricConfig_setBuckets0(
356    _env: JNIEnv,
357    _class: JClass,
358    ptr: jlong,
359    buckets: JDoubleArray,
360) {
361    if ptr == 0 {
362        return;
363    }
364    
365    let len = match _env.get_array_length(&buckets) {
366        Ok(len) => len,
367        Err(_) => return,
368    };
369    let mut buf = vec![0f64; len.max(0) as usize];
370    if _env.get_double_array_region(&buckets, 0, &mut buf).is_err() {
371        return;
372    }
373
374    let config = unsafe { &mut *(ptr as *mut RiMetricConfig) };
375    config.buckets = buf;
376}
377
378#[no_mangle]
379pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricConfig_setQuantiles0(
380    _env: JNIEnv,
381    _class: JClass,
382    ptr: jlong,
383    quantiles: JDoubleArray,
384) {
385    if ptr == 0 {
386        return;
387    }
388    
389    let len = match _env.get_array_length(&quantiles) {
390        Ok(len) => len,
391        Err(_) => return,
392    };
393    let mut buf = vec![0f64; len.max(0) as usize];
394    if _env.get_double_array_region(&quantiles, 0, &mut buf).is_err() {
395        return;
396    }
397
398    let config = unsafe { &mut *(ptr as *mut RiMetricConfig) };
399    config.quantiles = buf;
400}
401
402#[no_mangle]
403pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricConfig_free0(
404    _env: JNIEnv,
405    _class: JClass,
406    ptr: jlong,
407) {
408    if ptr != 0 {
409        unsafe {
410            let _ = Box::from_raw(ptr as *mut RiMetricConfig);
411        }
412    }
413}
414
415// RiMetric JNI bindings
416#[no_mangle]
417pub extern "system" fn Java_com_dunimd_ri_observability_RiMetric_new0(
418    _env: JNIEnv,
419    _class: JClass,
420    config_ptr: jlong,
421) -> jlong {
422    if config_ptr == 0 {
423        return 0;
424    }
425    
426    let config = unsafe { &*(config_ptr as *const RiMetricConfig) };
427    let metric = Box::new(std::sync::Arc::new(RiMetric::new(config.clone())));
428    Box::into_raw(metric) as jlong
429}
430
431#[no_mangle]
432pub extern "system" fn Java_com_dunimd_ri_observability_RiMetric_record0(
433    _env: JNIEnv,
434    _class: JClass,
435    ptr: jlong,
436    value: jdouble,
437) {
438    if ptr == 0 {
439        return;
440    }
441    
442    let metric = unsafe { &*(ptr as *const std::sync::Arc<RiMetric>) };
443    let _ = metric.record(value, vec![]);
444}
445
446#[no_mangle]
447pub extern "system" fn Java_com_dunimd_ri_observability_RiMetric_getValue0(
448    _env: JNIEnv,
449    _class: JClass,
450    ptr: jlong,
451) -> jdouble {
452    if ptr == 0 {
453        return 0.0;
454    }
455    
456    let metric = unsafe { &*(ptr as *const std::sync::Arc<RiMetric>) };
457    metric.get_value()
458}
459
460#[no_mangle]
461pub extern "system" fn Java_com_dunimd_ri_observability_RiMetric_getTotalCount0(
462    _env: JNIEnv,
463    _class: JClass,
464    ptr: jlong,
465) -> jlong {
466    if ptr == 0 {
467        return 0;
468    }
469    
470    let metric = unsafe { &*(ptr as *const std::sync::Arc<RiMetric>) };
471    metric.get_total_count() as jlong
472}
473
474#[no_mangle]
475pub extern "system" fn Java_com_dunimd_ri_observability_RiMetric_free0(
476    _env: JNIEnv,
477    _class: JClass,
478    ptr: jlong,
479) {
480    if ptr != 0 {
481        unsafe {
482            let _ = Box::from_raw(ptr as *mut std::sync::Arc<RiMetric>);
483        }
484    }
485}
486
487// RiMetricsRegistry JNI bindings
488#[no_mangle]
489pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_new0(
490    _env: JNIEnv,
491    _class: JClass,
492) -> jlong {
493    let registry = Box::new(RiMetricsRegistry::new());
494    Box::into_raw(registry) as jlong
495}
496
497#[no_mangle]
498pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_register0(
499    _env: JNIEnv,
500    _class: JClass,
501    ptr: jlong,
502    metric_ptr: jlong,
503) {
504    if ptr == 0 || metric_ptr == 0 {
505        return;
506    }
507    
508    let registry = unsafe { &*(ptr as *const RiMetricsRegistry) };
509    // metric_ptr 指向 Box<Arc<RiMetric>>:解出 Arc 后 clone 注册,
510    // 原指针回放(Box 重新装箱),Java 侧所有权保持不变。
511    let metric_arc = unsafe {
512        let boxed = Box::from_raw(metric_ptr as *mut std::sync::Arc<RiMetric>);
513        let arc = std::sync::Arc::clone(&boxed);
514        std::mem::forget(boxed);
515        arc
516    };
517    let _ = registry.register(metric_arc);
518}
519
520#[no_mangle]
521pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_get0(
522    mut env: JNIEnv,
523    _class: JClass,
524    ptr: jlong,
525    name: JString,
526) -> jlong {
527    if ptr == 0 {
528        return 0;
529    }
530    
531    let registry = unsafe { &*(ptr as *const RiMetricsRegistry) };
532    let name_str: String = match env.get_string(&name) {
533        Ok(s) => s.into(),
534        Err(_) => return 0,
535    };
536    
537    match registry.get_metric(&name_str) {
538        // 返回 registry 内真实实例的共享 Arc(新 Box 包装),
539        // Java record 的数据与 registry 中同一实例。
540        Some(metric) => Box::into_raw(Box::new(std::sync::Arc::clone(&metric))) as jlong,
541        None => 0,
542    }
543}
544
545#[no_mangle]
546pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_getMetricValue0(
547    mut env: JNIEnv,
548    _class: JClass,
549    ptr: jlong,
550    name: JString,
551) -> jdouble {
552    if ptr == 0 {
553        return 0.0;
554    }
555    
556    let registry = unsafe { &*(ptr as *const RiMetricsRegistry) };
557    let name_str: String = match env.get_string(&name) {
558        Ok(s) => s.into(),
559        Err(_) => return 0.0,
560    };
561    
562    match registry.get_metric(&name_str) {
563        Some(metric) => metric.get_value(),
564        None => 0.0,
565    }
566}
567
568#[no_mangle]
569pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_getAllMetricNames0(
570    mut env: JNIEnv,
571    _class: JClass,
572    ptr: jlong,
573) -> jobjectArray {
574    if ptr == 0 {
575        return std::ptr::null_mut();
576    }
577    
578    let registry = unsafe { &*(ptr as *const RiMetricsRegistry) };
579    let names: Vec<String> = registry.get_all_metrics().keys().cloned().collect();
580    
581    let array = match env.new_object_array(names.len() as jint, "java/lang/String", JObject::null()) {
582        Ok(arr) => arr,
583        Err(_) => return std::ptr::null_mut(),
584    };
585    
586    for (i, name) in names.iter().enumerate() {
587        if let Ok(jstr) = env.new_string(name) {
588            let _ = env.set_object_array_element(&array, i as jint, jstr);
589        }
590    }
591    
592    array.into_raw()
593}
594
595#[no_mangle]
596pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_exportPrometheus0(
597    _env: JNIEnv,
598    _class: JClass,
599    ptr: jlong,
600) -> jstring {
601    if ptr == 0 {
602        return std::ptr::null_mut();
603    }
604    
605    let registry = unsafe { &*(ptr as *const RiMetricsRegistry) };
606    let output = registry.export_prometheus();
607    
608    match _env.new_string(&output) {
609        Ok(s) => s.into_raw(),
610        Err(_) => std::ptr::null_mut(),
611    }
612}
613
614#[no_mangle]
615pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_getMetricCount0(
616    _env: JNIEnv,
617    _class: JClass,
618    ptr: jlong,
619) -> jint {
620    if ptr == 0 {
621        return 0;
622    }
623    
624    let registry = unsafe { &*(ptr as *const RiMetricsRegistry) };
625    registry.get_all_metrics().len() as jint
626}
627
628#[no_mangle]
629pub extern "system" fn Java_com_dunimd_ri_observability_RiMetricsRegistry_free0(
630    _env: JNIEnv,
631    _class: JClass,
632    ptr: jlong,
633) {
634    if ptr != 0 {
635        unsafe {
636            let _ = Box::from_raw(ptr as *mut RiMetricsRegistry);
637        }
638    }
639}
640
641// RiSystemMetricsCollector JNI bindings (only available with system_info feature)
642#[cfg(feature = "system_info")]
643#[no_mangle]
644pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_new0(
645    _env: JNIEnv,
646    _class: JClass,
647) -> jlong {
648    let collector = Box::new(RiSystemMetricsCollector::new());
649    Box::into_raw(collector) as jlong
650}
651
652#[cfg(feature = "system_info")]
653#[no_mangle]
654pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_collect0(
655    mut env: JNIEnv,
656    _class: JClass,
657    ptr: jlong,
658) -> jobject {
659    if ptr == 0 {
660        return JObject::null().into_raw();
661    }
662    
663    let collector = unsafe { &mut *(ptr as *mut RiSystemMetricsCollector) };
664    let metrics = collector.collect();
665    
666    create_system_metrics_object(&mut env, &metrics)
667}
668
669#[cfg(feature = "system_info")]
670fn create_system_metrics_object(env: &mut JNIEnv, metrics: &RiSystemMetrics) -> jobject {
671    let cpu_obj = create_cpu_metrics_object(env, &metrics.cpu);
672    let memory_obj = create_memory_metrics_object(env, &metrics.memory);
673    let disk_obj = create_disk_metrics_object(env, &metrics.disk);
674    let network_obj = create_network_metrics_object(env, &metrics.network);
675    
676    let cpu_jobj = match cpu_obj {
677        Ok(obj) => obj,
678        Err(_) => return JObject::null().into_raw(),
679    };
680    let memory_jobj = match memory_obj {
681        Ok(obj) => obj,
682        Err(_) => return JObject::null().into_raw(),
683    };
684    let disk_jobj = match disk_obj {
685        Ok(obj) => obj,
686        Err(_) => return JObject::null().into_raw(),
687    };
688    let network_jobj = match network_obj {
689        Ok(obj) => obj,
690        Err(_) => return JObject::null().into_raw(),
691    };
692    
693    match env.new_object(
694        "com/dunimd/ri/observability/RiSystemMetrics",
695        "(Lcom/dunimd/ri/observability/RiCPUMetrics;Lcom/dunimd/ri/observability/RiMemoryMetrics;Lcom/dunimd/ri/observability/RiDiskMetrics;Lcom/dunimd/ri/observability/RiNetworkMetrics;J)V",
696        &[
697            JValue::Object(&cpu_jobj),
698            JValue::Object(&memory_jobj),
699            JValue::Object(&disk_jobj),
700            JValue::Object(&network_jobj),
701            (metrics.timestamp as jlong).into(),
702        ],
703    ) {
704        Ok(obj) => obj.into_raw(),
705        Err(_) => JObject::null().into_raw(),
706    }
707}
708
709#[cfg(feature = "system_info")]
710fn create_cpu_metrics_object<'local>(env: &mut JNIEnv<'local>, cpu: &RiCPUMetrics) -> jni::errors::Result<JObject<'local>> {
711    let per_core_array = env.new_double_array(cpu.per_core_usage.len() as jint)?;
712    env.set_double_array_region(&per_core_array, 0, &cpu.per_core_usage)?;
713    
714    env.new_object(
715        "com/dunimd/ri/observability/RiCPUMetrics",
716        "(D[DJJ)V",
717        &[
718            cpu.total_usage_percent.into(),
719            JValue::Object(&per_core_array),
720            (cpu.context_switches as jlong).into(),
721            (cpu.interrupts as jlong).into(),
722        ],
723    )
724}
725
726#[cfg(feature = "system_info")]
727fn create_memory_metrics_object<'local>(env: &mut JNIEnv<'local>, memory: &RiMemoryMetrics) -> jni::errors::Result<JObject<'local>> {
728    env.new_object(
729        "com/dunimd/ri/observability/RiMemoryMetrics",
730        "(JJJDJJDD)V",
731        &[
732            (memory.total_bytes as jlong).into(),
733            (memory.used_bytes as jlong).into(),
734            (memory.free_bytes as jlong).into(),
735            memory.usage_percent.into(),
736            (memory.swap_total_bytes as jlong).into(),
737            (memory.swap_used_bytes as jlong).into(),
738            (memory.swap_free_bytes as jlong).into(),
739            memory.swap_usage_percent.into(),
740        ],
741    )
742}
743
744#[cfg(feature = "system_info")]
745fn create_disk_metrics_object<'local>(env: &mut JNIEnv<'local>, disk: &RiDiskMetrics) -> jni::errors::Result<JObject<'local>> {
746    env.new_object(
747        "com/dunimd/ri/observability/RiDiskMetrics",
748        "(JJJDJJJJ)V",
749        &[
750            (disk.total_bytes as jlong).into(),
751            (disk.used_bytes as jlong).into(),
752            (disk.free_bytes as jlong).into(),
753            disk.usage_percent.into(),
754            (disk.read_bytes as jlong).into(),
755            (disk.write_bytes as jlong).into(),
756            (disk.read_count as jlong).into(),
757            (disk.write_count as jlong).into(),
758        ],
759    )
760}
761
762#[cfg(feature = "system_info")]
763fn create_network_metrics_object<'local>(env: &mut JNIEnv<'local>, network: &RiNetworkMetrics) -> jni::errors::Result<JObject<'local>> {
764    env.new_object(
765        "com/dunimd/ri/observability/RiNetworkMetrics",
766        "(JJJJJJJJ)V",
767        &[
768            (network.total_received_bytes as jlong).into(),
769            (network.total_transmitted_bytes as jlong).into(),
770            (network.received_bytes_per_sec as jlong).into(),
771            (network.transmitted_bytes_per_sec as jlong).into(),
772            (network.total_received_packets as jlong).into(),
773            (network.total_transmitted_packets as jlong).into(),
774            (network.received_packets_per_sec as jlong).into(),
775            (network.transmitted_packets_per_sec as jlong).into(),
776        ],
777    )
778}
779
780#[cfg(feature = "system_info")]
781#[no_mangle]
782pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_refresh0(
783    _env: JNIEnv,
784    _class: JClass,
785    ptr: jlong,
786) {
787    if ptr == 0 {
788        return;
789    }
790    
791    let collector = unsafe { &mut *(ptr as *mut RiSystemMetricsCollector) };
792    collector.refresh();
793}
794
795#[cfg(feature = "system_info")]
796#[no_mangle]
797pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_free0(
798    _env: JNIEnv,
799    _class: JClass,
800    ptr: jlong,
801) {
802    if ptr != 0 {
803        unsafe {
804            let _ = Box::from_raw(ptr as *mut RiSystemMetricsCollector);
805        }
806    }
807}
808
809// Stub implementations when system_info feature is not enabled
810#[cfg(not(feature = "system_info"))]
811#[no_mangle]
812pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_new0(
813    _env: JNIEnv,
814    _class: JClass,
815) -> jlong {
816    0
817}
818
819#[cfg(not(feature = "system_info"))]
820#[no_mangle]
821pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_collect0(
822    _env: JNIEnv,
823    _class: JClass,
824    _ptr: jlong,
825) -> jobject {
826    JObject::null().into_raw()
827}
828
829#[cfg(not(feature = "system_info"))]
830#[no_mangle]
831pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_refresh0(
832    _env: JNIEnv,
833    _class: JClass,
834    _ptr: jlong,
835) {
836}
837
838#[cfg(not(feature = "system_info"))]
839#[no_mangle]
840pub extern "system" fn Java_com_dunimd_ri_observability_RiSystemMetricsCollector_free0(
841    _env: JNIEnv,
842    _class: JClass,
843    _ptr: jlong,
844) {
845}