Skip to content

Commit

Permalink
add system stats subscriber
Browse files Browse the repository at this point in the history
  • Loading branch information
dheera committed Aug 16, 2021
1 parent 3b39da2 commit 1b2e677
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 29 deletions.
8 changes: 7 additions & 1 deletion rosboard/html/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,13 @@ let onTopics = function(topics) {
$('<a></a>')
.addClass("mdl-navigation__link")
.click(() => { initSubscribe({topicName: "_top", topicType: "rosboard_msgs/msg/ProcessList"}); })
.text("top")
.text("Processes")
.appendTo($("#topics-nav-system"));

$('<a></a>')
.addClass("mdl-navigation__link")
.click(() => { initSubscribe({topicName: "_system_stats", topicType: "rosboard_msgs/msg/SystemStats"}); })
.text("System stats")
.appendTo($("#topics-nav-system"));
}

Expand Down
30 changes: 30 additions & 0 deletions rosboard/rosboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from rosboard.serialization import ros2dict
from rosboard.subscribers.dmesg_subscriber import DMesgSubscriber
from rosboard.subscribers.processes_subscriber import ProcessesSubscriber
from rosboard.subscribers.system_stats_subscriber import SystemStatsSubscriber
from rosboard.subscribers.dummy_subscriber import DummySubscriber
from rosboard.handlers import ROSBoardSocketHandler, NoCacheStaticFileHandler

Expand Down Expand Up @@ -181,6 +182,12 @@ def sync_subs(self):
self.local_subs[topic_name] = DMesgSubscriber(self.on_dmesg)
continue

if topic_name == "_system_stats":
if topic_name not in self.local_subs:
rospy.loginfo("Subscribing to _system_stats [non-ros]")
self.local_subs[topic_name] = SystemStatsSubscriber(self.on_system_stats)
continue

if topic_name == "_top":
if topic_name not in self.local_subs:
rospy.loginfo("Subscribing to _top [non-ros]")
Expand Down Expand Up @@ -240,6 +247,29 @@ def sync_subs(self):

self.lock.release()

def on_system_stats(self, system_stats):
"""
system stats received. send it off to the client as a "fake" ROS message (which could at some point be a real ROS message)
"""
if self.event_loop is None:
return

msg_dict = {
"_topic_name": "_system_stats", # special non-ros topics start with _
"_topic_type": "rosboard_msgs/msg/SystemStats",
}

for key, value in system_stats.items():
msg_dict[key] = value

self.event_loop.add_callback(
ROSBoardSocketHandler.broadcast,
[
ROSBoardSocketHandler.MSG_MSG,
msg_dict
]
)

def on_top(self, processes):
"""
processes list received. send it off to the client as a "fake" ROS message (which could at some point be a real ROS message)
Expand Down
75 changes: 47 additions & 28 deletions rosboard/subscribers/system_stats_subscriber.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,69 @@
#!/usr/bin/env python3

import psutil
import select
import subprocess
try:
import psutil
except (ImportError, ModuleNotFoundError) as e:
psutil = None

import time
import threading
import traceback

def mean(list):
return sum(list)/len(list)

class SystemStatsSubscriber(object):
def __init__(self, callback):
self.callback = callback
self.process = None
self.stop = False
threading.Thread(target = self.start, daemon = True).start()

def __del__(self):
if self.process:
self.process.terminate()
self.process = None
self.stop = True
pass

def unregister(self):
if self.process:
self.process.terminate()
self.process = None
self.stop = True
pass

def start(self):
try:
self.process = subprocess.Popen(['dmesg', '--follow'], stdout = subprocess.PIPE)
p = select.poll()
p.register(self.process.stdout, select.POLLIN)

while True:
time.sleep(0.1)

if self.process is None:
break
if psutil is None:
self.callback({"_error": "Please install psutil (sudo pip3 install --upgrade psutil) to use this feature."})
return

while not self.stop:
try:
p = psutil.Process()

with p.oneshot():
sensors_temperatures = psutil.sensors_temperatures()
cpu_percent = psutil.cpu_percent(percpu = True)
net_io_counters = psutil.net_io_counters()
virtual_memory = psutil.virtual_memory()
swap_memory = psutil.swap_memory()
disk_usage = psutil.disk_usage('/')

status = {}

status["cpu_percent"] = cpu_percent

if "coretemp" in sensors_temperatures:
status["temp_coretemp"] = mean(list(map(
lambda x:x.current,
sensors_temperatures["coretemp"]
)))

lines = []
while p.poll(1):
lines.append(self.process.stdout.readline().decode('utf-8').strip())
status["net_bytes_sent"] = net_io_counters.bytes_sent
status["net_bytes_recv"] = net_io_counters.bytes_recv
status["disk_usage_percent"] = disk_usage.percent
status["virtual_memory_percent"] = virtual_memory.percent
status["swap_memory_percent"] = swap_memory.percent

text = "\n".join(lines)
if len(text) > 0:
self.callback("\n".join(lines))
except:
traceback.print_exc()
except Exception as e:
traceback.print_exc()

self.callback(status)
time.sleep(3)

if __name__ == "__main__":
# Run test
Expand Down

0 comments on commit 1b2e677

Please sign in to comment.