summaryrefslogtreecommitdiffstats
path: root/glances/amps/amp.py
diff options
context:
space:
mode:
Diffstat (limited to 'glances/amps/amp.py')
-rw-r--r--glances/amps/amp.py197
1 files changed, 197 insertions, 0 deletions
diff --git a/glances/amps/amp.py b/glances/amps/amp.py
new file mode 100644
index 00000000..41881ea8
--- /dev/null
+++ b/glances/amps/amp.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Glances.
+#
+# SPDX-FileCopyrightText: 2023 Nicolas Hennion <nicolas@nicolargo.com>
+#
+# SPDX-License-Identifier: LGPL-3.0-only
+#
+
+"""
+I am your father...
+
+...for all Glances Application Monitoring Processes (AMP).
+
+AMP (Application Monitoring Process)
+A Glances AMP is a Python script called (every *refresh* seconds) if:
+- the AMP is *enabled* in the Glances configuration file
+- a process is running (match the *regex* define in the configuration file)
+The script should define a Amp (GlancesAmp) class with, at least, an update method.
+The update method should call the set_result method to set the AMP return string.
+The return string is a string with one or more line (\n between lines).
+If the *one_line* var is true then the AMP will be displayed in one line.
+"""
+
+from glances.globals import u
+from glances.timer import Timer
+from glances.logger import logger
+
+
+class GlancesAmp(object):
+ """Main class for Glances AMP."""
+
+ NAME = '?'
+ VERSION = '?'
+ DESCRIPTION = '?'
+ AUTHOR = '?'
+ EMAIL = '?'
+
+ def __init__(self, name=None, args=None):
+ """Init AMP class."""
+ logger.debug("AMP - Init {} version {}".format(self.NAME, self.VERSION))
+
+ # AMP name (= module name without glances_)
+ if name is None:
+ self.amp_name = self.__class__.__module__
+ else:
+ self.amp_name = name
+
+ # Init the args
+ self.args = args
+
+ # Init the configs
+ self.configs = {}
+
+ # A timer is needed to only update every refresh seconds
+ # Init to 0 in order to update the AMP on startup
+ self.timer = Timer(0)
+
+ def load_config(self, config):
+ """Load AMP parameters from the configuration file."""
+
+ # Read AMP configuration.
+ # For ex, the AMP foo should have the following section:
+ #
+ # [foo]
+ # enable=true
+ # regex=\/usr\/bin\/nginx
+ # refresh=60
+ #
+ # and optionally:
+ #
+ # one_line=false
+ # option1=opt1
+
+ amp_section = 'amp_' + self.amp_name
+ if hasattr(config, 'has_section') and config.has_section(amp_section):
+ logger.debug("AMP - {}: Load configuration".format(self.NAME))
+ for param, _ in config.items(amp_section):
+ try:
+ self.configs[param] = config.get_float_value(amp_section, param)
+ except ValueError:
+ self.configs[param] = config.get_value(amp_section, param).split(',')
+ if len(self.configs[param]) == 1:
+ self.configs[param] = self.configs[param][0]
+ logger.debug("AMP - {}: Load parameter: {} = {}".format(self.NAME, param, self.configs[param]))
+ else:
+ logger.debug("AMP - {}: Can not find section {} in the configuration file".format(self.NAME, self.amp_name))
+ return False
+
+ if self.enable():
+ # Refresh option is mandatory
+ for k in ['refresh']:
+ if k not in self.configs:
+ logger.warning(
+ "AMP - {}: Can not find configuration key {} in section {} (the AMP will be disabled)".format(
+ self.NAME, k, self.amp_name
+ )
+ )
+ self.configs['enable'] = 'false'
+ else:
+ logger.debug("AMP - {} is disabled".format(self.NAME))
+
+ # Init the count to 0
+ self.configs['count'] = 0
+
+ return self.enable()
+
+ def get(self, key):
+ """Generic method to get the item in the AMP configuration"""
+ if key in self.configs:
+ return self.configs[key]
+ else:
+ return None
+
+ def enable(self):
+ """Return True|False if the AMP is enabled in the configuration file (enable=true|false)."""
+ ret = self.get('enable')
+ if ret is None:
+ return False
+ else:
+ return ret.lower().startswith('true')
+
+ def regex(self):
+ """Return regular expression used to identified the current application."""
+ return self.get('regex')
+
+ def refresh(self):
+ """Return refresh time in seconds for the current application monitoring process."""
+ return self.get('refresh')
+
+ def one_line(self):
+ """Return True|False if the AMP should be displayed in one line (one_line=true|false)."""
+ ret = self.get('one_line')
+ if ret is None:
+ return False
+ else:
+ return ret.lower().startswith('true')
+
+ def time_until_refresh(self):
+ """Return time in seconds until refresh."""
+ return self.timer.get()
+
+ def should_update(self):
+ """Return True is the AMP should be updated
+
+ Conditions for update:
+ - AMP is enable
+ - only update every 'refresh' seconds
+ """
+ if self.timer.finished():
+ self.timer.set(self.refresh())
+ self.timer.reset()
+ return self.enable()
+ return False
+
+ def set_count(self, count):
+ """Set the number of processes matching the regex"""
+ self.configs['count'] = count
+
+ def count(self):
+ """Get the number of processes matching the regex"""
+ return self.get('count')
+
+ def count_min(self):
+ """Get the minimum number of processes"""
+ return self.get('countmin')
+
+ def count_max(self):
+ """Get the maximum number of processes"""
+ return self.get('countmax')
+
+ def set_result(self, result, separator=''):
+ """Store the result (string) into the result key of the AMP
+
+ If one_line is true then it replaces `\n` by the separator
+ """
+ if self.one_line():
+ self.configs['result'] = u(result).replace('\n', separator)
+ else:
+ self.configs['result'] = u(result)
+
+ def result(self):
+ """Return the result of the AMP (as a string)"""
+ ret = self.get('result')
+ if ret is not None:
+ ret = u(ret)
+ return ret
+
+ def update_wrapper(self, process_list):
+ """Wrapper for the children update"""
+ # Set the number of running process
+ self.set_count(len(process_list))
+ # Call the children update method
+ if self.should_update():
+ return self.update(process_list)
+ else:
+ return self.result()