import sys
import time
-
+# -----------------------------------------------------------------------------
+# globals & environment setup
+# https://github.com/firehol/netdata/wiki/External-Plugins#environment-variables
MODULE_EXTENSION = ".chart.py"
-BASE_CONFIG = {'update_every': 1,
+BASE_CONFIG = {'update_every': os.getenv('NETDATA_UPDATE_EVERY', 1),
'priority': 90000,
'retries': 10}
-
-# -----------------------------------------------------------------------------
-# logging functions
+MODULES_DIR = os.path.abspath(os.getenv('NETDATA_PLUGINS_DIR',
+ os.path.dirname(__file__)) + "/../python.d") + "/"
+CONFIG_DIR = os.getenv('NETDATA_CONFIG_DIR', "/etc/netdata/")
+# directories should end with '/'
+if CONFIG_DIR[-1] != "/":
+ CONFIG_DIR += "/"
+sys.path.append(MODULES_DIR + "python_modules")
PROGRAM = os.path.basename(__file__).replace(".plugin", "")
DEBUG_FLAG = False
+OVERRIDE_UPDATE_EVERY = False
-def debug(*args):
+
+# -----------------------------------------------------------------------------
+# logging functions
+def log_msg(msg_type, *args):
"""
Print message on stderr.
+ :param msg_type: str
"""
- if not DEBUG_FLAG:
- return
- sys.stderr.write(PROGRAM + " DEBUG :")
+ sys.stderr.write(PROGRAM)
+ sys.stderr.write(" ")
+ sys.stderr.write(msg_type)
+ sys.stderr.write(": ")
for i in args:
- sys.stderr.write(" " + str(i))
+ sys.stderr.write(" ")
+ sys.stderr.write(str(i))
sys.stderr.write("\n")
sys.stderr.flush()
+
+def debug(*args):
+ """
+ Print debug message on stderr.
+ """
+ if not DEBUG_FLAG:
+ return
+
+ log_msg("DEBUG", *args)
+
+
def error(*args):
"""
Print message on stderr.
"""
- sys.stderr.write(PROGRAM + " ERROR :")
- for i in args:
- sys.stderr.write(" " + str(i))
- sys.stderr.write("\n")
- sys.stderr.flush()
+ log_msg("ERROR", *args)
+
def info(*args):
"""
Print message on stderr.
"""
- sys.stderr.write(PROGRAM + " INFO :")
- for i in args:
- sys.stderr.write(" " + str(i))
- sys.stderr.write("\n")
- sys.stderr.flush()
+ log_msg("INFO", *args)
+
def fatal(*args):
"""
Print message on stderr and exit.
"""
- sys.stderr.write(PROGRAM + " FATAL :")
- for i in args:
- sys.stderr.write(" " + str(i))
- sys.stderr.write("\n")
- sys.stderr.flush()
+ log_msg("FATAL", *args)
sys.stdout.write('DISABLE\n')
sys.exit(1)
-
# -----------------------------------------------------------------------------
-# globals & python modules management
-
-# setup environment
-# https://github.com/firehol/netdata/wiki/External-Plugins#environment-variables
-MODULES_DIR = os.path.abspath(os.getenv('NETDATA_PLUGINS_DIR',
- os.path.dirname(__file__)) + "/../python.d") + "/"
-CONFIG_DIR = os.getenv('NETDATA_CONFIG_DIR', "/etc/netdata/")
-UPDATE_EVERY = os.getenv('NETDATA_UPDATE_EVERY', 1)
-# directories should end with '/'
-if CONFIG_DIR[-1] != "/":
- CONFIG_DIR += "/"
-sys.path.append(MODULES_DIR + "python_modules")
-
+# third party and version specific python modules management
try:
assert sys.version_info >= (3, 1)
import importlib.machinery
except ImportError:
fatal('Cannot find yaml library')
+
class PythonCharts(object):
"""
Main class used to control every python module.
"""
def __init__(self,
- update_every=None,
modules=None,
modules_path='../python.d/',
modules_configs='../conf.d/',
modules_disabled=None):
"""
- :param update_every: int
:param modules: list
:param modules_path: str
:param modules_configs: str
# good economy and prosperity:
self.jobs = self._create_jobs(configured_modules) # type: list
- if DEBUG_FLAG and update_every is not None:
+
+ # enable timetable override like `python.d.plugin mysql debug 1`
+ if DEBUG_FLAG and OVERRIDE_UPDATE_EVERY:
for job in self.jobs:
- job.create_timetable(update_every)
+ job.create_timetable(BASE_CONFIG['update_every'])
@staticmethod
def _import_module(path, name=None):
else:
return imp.load_source(name, path)
except Exception as e:
- debug(str(e))
+ debug("Problem loading", name, str(e))
return None
def _load_modules(self, path, modules, disabled):
error(mod.__name__ + ": configuration file '" + configfile + "' not found. Using defaults.")
# set config if not found
if not hasattr(mod, 'config'):
+ debug(mod.__name__ + ": setting configuration for only one job")
mod.config = {None: {}}
for var in BASE_CONFIG:
try:
# get default values
defaults = {}
for key in BASE_CONFIG:
+ debug(module.__name__ + ": reading configuration")
try:
# get defaults from module config
defaults[key] = int(config.pop(key))
if not job.check():
self._stop(job, "failed check")
else:
+ debug(job.name, ": check succeeded")
i += 1
except AttributeError:
self._stop(job, "no check")
except (UnboundLocalError, Exception) as e:
- self._stop(job, "misbehaving. Reason: " + str(e))
+ self._stop(job, "misbehaving. Reason:" + str(e))
def create(self):
"""
str(job.timetable['freq']) +
'\n')
sys.stdout.write("DIMENSION run_time 'run time' absolute 1 1\n\n")
+ debug("created charts for", job.chart_name)
# sys.stdout.flush()
i += 1
except AttributeError:
t_start = time.time()
# check if it is time to execute job update() function
if job.timetable['next'] > t_start:
+ debug("it is not a time to invoke update on", job.chart_name)
return True
try:
if self.first_run:
t_end = time.time()
job.timetable['next'] = t_end - (t_end % job.timetable['freq']) + job.timetable['freq']
# draw performance graph
+ run_time = str(int((t_end - t_start) * 1000))
+ debug(job.chart_name, "updated in", run_time)
sys.stdout.write("BEGIN netdata.plugin_pythond_" + job.chart_name + " " + str(since_last) + '\n')
- sys.stdout.write("SET run_time = " + str(int((t_end - t_start) * 1000)) + '\n')
+ sys.stdout.write("SET run_time = " + run_time + '\n')
sys.stdout.write("END\n")
# sys.stdout.flush()
job.timetable['last'] = t_start
:return: dict
"""
global DEBUG_FLAG
- global UPDATE_EVERY
- update_every = UPDATE_EVERY
+ global OVERRIDE_UPDATE_EVERY
+ global BASE_CONFIG
mods = []
for cmd in commands[1:]:
mods.append(cmd.replace(".chart.py", ""))
else:
try:
- update_every = int(cmd)
+ BASE_CONFIG['update_every'] = int(cmd)
+ OVERRIDE_UPDATE_EVERY = True
+ debug(PROGRAM, "overriding update interval to", str(int(cmd)))
except ValueError:
- update_every = UPDATE_EVERY
+ pass
debug("started from", commands[0], "with options:", *commands[1:])
- UPDATE_EVERY = update_every
- return {'modules': mods}
+ return mods
# if __name__ == '__main__':
"""
Main program.
"""
- global PROGRAM, DEBUG_FLAG
- PROGRAM = sys.argv[0].split('/')[-1].split('.plugin')[0]
+ global DEBUG_FLAG, BASE_CONFIG
# read configuration file
disabled = []
configfile = CONFIG_DIR + "python.d.conf"
+ debug(PROGRAM, "reading configuration file:", configfile)
- update_every = UPDATE_EVERY
conf = read_config(configfile)
if conf is not None:
try:
- # FIXME: is this right? exit the whole plugin?
- if str(conf['enable']) is False:
+ # exit the whole plugin when 'enabled: no' is set in 'python.d.conf'
+ if conf['enabled'] is False:
fatal('disabled in configuration file.\n')
except (KeyError, TypeError):
pass
try:
- update_every = conf['update_every']
+ for param in BASE_CONFIG:
+ BASE_CONFIG[param] = conf[param]
except (KeyError, TypeError):
pass # use default update_every from NETDATA_UPDATE_EVERY
try:
except (KeyError, TypeError):
pass
for k, v in conf.items():
- if k in ("update_every", "debug", "enable"):
+ if k in ("update_every", "debug", "enabled"):
continue
if v is False:
disabled.append(k)
# parse passed command line arguments
- out = parse_cmdline(MODULES_DIR, *sys.argv)
- modules = out['modules']
- info("MODULES_DIR='" + MODULES_DIR + "', CONFIG_DIR='" + CONFIG_DIR + "', UPDATE_EVERY=" + str(UPDATE_EVERY) + ", ONLY_MODULES=" + str(out['modules']))
+ modules = parse_cmdline(MODULES_DIR, *sys.argv)
+ info("MODULES_DIR='" + MODULES_DIR +
+ "', CONFIG_DIR='" + CONFIG_DIR +
+ "', UPDATE_EVERY=" + str(BASE_CONFIG['update_every']) +
+ ", ONLY_MODULES=" + str(modules))
# run plugins
- charts = PythonCharts(update_every, modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled)
+ charts = PythonCharts(modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled)
charts.check()
charts.create()
charts.update()