Index: /branches/rel_apv_10_7_4/usr/click/tools/prometheus_client/prometheus_client_service.py
===================================================================
--- /branches/rel_apv_10_7_4/usr/click/tools/prometheus_client/prometheus_client_service.py	(revision 40085)
+++ /branches/rel_apv_10_7_4/usr/click/tools/prometheus_client/prometheus_client_service.py	(working copy)
@@ -31,25 +31,25 @@
 registry = CollectorRegistry()
 
 cpu_usage = Gauge(
-        'cpu_usage', 
-        'Current CPU usage(%)', 
-        ['core'], 
+        'cpu_usage',
+        'Current CPU usage(%)',
+        ['core'],
         registry=registry
     )
 metrics_list.append(cpu_usage)
 
 memory_status = Gauge(
-        'memory_status', 
-        'Represents the current memory usage status of the system, including total, used, available, and usage percentage. Unit in MB.', 
-        ['status'], 
+        'memory_status',
+        'Represents the current memory usage status of the system, including total, used, available, and usage percentage. Unit in MB.',
+        ['status'],
         registry=registry
     )
 metrics_list.append(memory_status)
 
 disk_status = Gauge(
-        'disk_status', 
-        'Monitor the disk usage, including total, used, free, and usage percent. Unit in GB.', 
-        ['status'], 
+        'disk_status',
+        'Monitor the disk usage, including total, used, free, and usage percent. Unit in GB.',
+        ['status'],
         registry=registry
     )
 metrics_list.append(disk_status)
@@ -154,6 +154,10 @@
     disk_status.labels(status='free').set(round(disk.free / bytes_per_gb, 2))
     disk_status.labels(status='usage').set(round(disk.percent, 2))
 
+from collections import namedtuple
+
+IOCounters = namedtuple('IOCounters', ['bytes_sent', 'bytes_recv'])
+
 def update_network_throughput():
     """
     @brief Update the Prometheus network_throughput metrics
@@ -164,39 +168,87 @@
 
     if net_io_new is not None:
         for io_new in net_io_new:
-            if ('atcp_veth' in io_new or 'atcp_vbond' in io_new) and io_new in net_io_old:
+            # Check if this interface exists in the old sample
+            if io_new in net_io_old:
                 io_data_new = net_io_new[io_new]
                 io_data_old = net_io_old[io_new]
-                name = None
-                if 'atcp_veth' in io_new:
-                    name = io_new.replace('atcp_veth', 'port')
-                elif 'atcp_vbond' in io_new:
-                    name = io_new.replace('atcp_vbond', 'bond')
 
+                name = io_new
                 if name is not None:
-                    tmp_up = ((io_data_new.bytes_sent - io_data_old.bytes_sent) / bytes_per_mb) / throughput_time
-                    tmp_down = ((io_data_new.bytes_recv - io_data_old.bytes_recv) / bytes_per_mb) / throughput_time
+                    # Mbps calculation: (delta_bytes * 8) / 1,000,000 / time
+                    # Standard network unit: 1 Mbps = 1,000,000 bits
+                    tmp_up = ((io_data_new.bytes_sent - io_data_old.bytes_sent) * 8 / 1000000) / throughput_time
+                    tmp_down = ((io_data_new.bytes_recv - io_data_old.bytes_recv) * 8 / 1000000) / throughput_time
+
+                    if tmp_up < 0: tmp_up = 0
+                    if tmp_down < 0: tmp_down = 0
 
                     network_throughput.labels(interface=f'{name}_up').set(round(tmp_up, 2))
                     network_throughput.labels(interface=f'{name}_down').set(round(tmp_down, 2))
 
-                    if 'atcp_veth' in name:
+                    if name.startswith('port'):
                         up += tmp_up
                         down += tmp_down
 
     network_throughput.labels(interface='total_up').set(round(up, 2))
     network_throughput.labels(interface='total_down').set(round(down, 2))
 
+def get_network_counters_cli():
+    """
+    @brief Get network counters from APV CLI "show interface"
+    @return dict of IOCounters
+    """
+    cmd = "/ca/bin/backend -c \"show interface\"`echo -e \"\\0374\"`"
+    try:
+        output_byte = subprocess.check_output(cmd, shell=True)
+    except Exception as e:
+        return {}
+
+    output_byte = output_byte.replace(b'\xfc', b'')
+    output = output_byte.decode('utf-8', errors='ignore')
+
+    res = {}
+
+    interface_pattern = r"([a-zA-Z0-9_]+)\([a-zA-Z0-9_]+\):"
+    parts = re.split(interface_pattern, output)
+
+    # Simplified regex using DOTALL to be more robust against whitespace/format variations
+    # Matches "Input queue: ... total: X packets, [good: Y packets,] Z bytes"
+    bytes_in_pattern = r"Input queue:.*?total:.*?(\d+)\s*bytes"
+    bytes_out_pattern = r"Output queue:.*?total:.*?(\d+)\s*bytes"
+
+    for i in range(1, len(parts), 2):
+        name = parts[i]
+        content = parts[i+1]
+
+        # Use re.DOTALL (re.S) so .*? matches newlines
+        bin_match = re.search(bytes_in_pattern, content, re.DOTALL)
+        bout_match = re.search(bytes_out_pattern, content, re.DOTALL)
+
+        bytes_in = 0
+        bytes_out = 0
+
+        if bin_match:
+            bytes_in = int(bin_match.group(1))
+
+        if bout_match:
+            bytes_out = int(bout_match.group(1))
+
+        # Always add the interface, even if stats are 0 or not found
+        res[name] = IOCounters(bytes_out, bytes_in)
+
+    return res
+
 def get_network_throughput():
     """
     @brief Regularly retrieve network_throughput data
     """
     global net_io_new, net_io_old
-    net_io_new = psutil.net_io_counters(pernic=True)
+    net_io_new = get_network_counters_cli()
     net_io_old = net_io_new
     while True:
         time.sleep(throughput_time)
-        net_io_new, net_io_old = psutil.net_io_counters(pernic=True), net_io_new
+        net_io_new, net_io_old = get_network_counters_cli(), net_io_new
 
 def update_start_time_seconds():
     """
@@ -269,4 +321,4 @@
     if args.show_metrics:
         show_metrics()
     else:
-        run_service()
\ No newline at end of file
+        run_service()
