diff --git a/diagnostic_common_diagnostics/CMakeLists.txt b/diagnostic_common_diagnostics/CMakeLists.txt index 43202b9e..42ad3e4e 100644 --- a/diagnostic_common_diagnostics/CMakeLists.txt +++ b/diagnostic_common_diagnostics/CMakeLists.txt @@ -10,6 +10,7 @@ ament_python_install_package(${PROJECT_NAME}) install(PROGRAMS ${PROJECT_NAME}/cpu_monitor.py ${PROJECT_NAME}/ntp_monitor.py + ${PROJECT_NAME}/ram_monitor.py DESTINATION lib/${PROJECT_NAME} ) diff --git a/diagnostic_common_diagnostics/README.md b/diagnostic_common_diagnostics/README.md index 95e41627..e0d75ab1 100644 --- a/diagnostic_common_diagnostics/README.md +++ b/diagnostic_common_diagnostics/README.md @@ -56,7 +56,27 @@ Disable self test. **To be ported** ## ram_monitor.py -**To be ported** +The `ram_monitor` module allows users to monitor the RAM usage of their system in real-time. +It publishes the usage percentage in a diagnostic message. + +* Name of the node is "ram_monitor_" + hostname. +* Uses the following args: + * warning_percentage: If the RAM usage is > warning_percentage, a WARN status will be published. + * window: the maximum length of the used collections.deque for queuing CPU readings. + +### Published Topics +#### /diagnostics +diagnostic_msgs/DiagnosticArray +The diagnostics information. + +### Parameters +#### warning_percentage +(default: 90) +warning percentage threshold. + +#### window +(default: 1) +Length of RAM readings queue. ## sensors_monitor.py **To be ported** diff --git a/diagnostic_common_diagnostics/diagnostic_common_diagnostics/ram_monitor.py b/diagnostic_common_diagnostics/diagnostic_common_diagnostics/ram_monitor.py new file mode 100755 index 00000000..15897cb6 --- /dev/null +++ b/diagnostic_common_diagnostics/diagnostic_common_diagnostics/ram_monitor.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# +# Software License Agreement (BSD License) +# +# Copyright (c) 2017, TNO IVS, Helmond, Netherlands +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of the TNO IVS nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# \author Rein Appeldoorn + +import collections +import socket + +import psutil +import rclpy +from diagnostic_msgs.msg import DiagnosticStatus +from diagnostic_updater import DiagnosticTask, Updater + + +class RamTask(DiagnosticTask): + def __init__(self, warning_percentage, window=1): + DiagnosticTask.__init__(self, "RAM Information") + self._warning_percentage = int(warning_percentage) + self._readings = collections.deque(maxlen=window) + + def run(self, stat): + self._readings.append(psutil.virtual_memory().percent) + ram_average = sum(self._readings) / len(self._readings) + + stat.add("RAM Load Average", "{:.2f}".format(ram_average)) + + if ram_average > self._warning_percentage: + stat.summary(DiagnosticStatus.WARN, + "RAM Average exceeds {:d} percent".format(self._warning_percentage)) + else: + stat.summary(DiagnosticStatus.OK, "RAM Average {:.2f} percent".format(ram_average)) + + return stat + + +def main(): + hostname = socket.gethostname() + rclpy.init() + node = rclpy.create_node('ram_monitor_%s' % hostname.replace("-", "_")) + + updater = Updater(node) + updater.setHardwareID(hostname) + updater.add( + RamTask(node.declare_parameter("warning_percentage", 90.0).value, node.declare_parameter("window", 1).value)) + + rclpy.spin(node) + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt as e: + pass