diff --git a/graphios.py b/graphios.py index 1ee2600..6d90e88 100755 --- a/graphios.py +++ b/graphios.py @@ -38,6 +38,7 @@ from optparse import OptionParser import copy import graphios_backends as backends +import imp import logging import logging.handlers import os @@ -216,7 +217,8 @@ def verify_config(config_dict): global spool_directory ensure_list = ['replacement_character', 'log_file', 'log_max_size', 'log_level', 'sleep_time', 'sleep_max', 'test_mode', - 'reverse_hostname', 'replace_hostname'] + 'reverse_hostname', 'replace_hostname', 'plugin_path', + 'override_with_plugin'] missing_values = [] for ensure in ensure_list: if ensure not in config_dict: @@ -228,6 +230,18 @@ def verify_config(config_dict): sys.exit(1) if "spool_directory" in config_dict: spool_directory = config_dict['spool_directory'] + if config_dict['override_with_plugin']: + plugin = try_load(config_dict['plugin_path']) + try: + plugin.get_metrics + except Exception as e: + print "Exception occured while loading plugin path %s:" \ + % (config_dict['plugin_path']) + print " %s" % e + print "Plugin must implement 'get_metrics' see \ + plugins/plugin_example.py" + print "Exiting." + exit(1) def print_debug(msg): @@ -348,6 +362,20 @@ def process_log(file_name): if mobj: # break out the metric object into one object per perfdata metric # log.debug('perfdata:%s' % mobj.PERFDATA) + # SERVICEPERFDATA::time=0.001402s;;;0.000000 size=11783B;;;0 + + if cfg['override_with_plugin']: + module = try_load(cfg['plugin_path']) + carbon_metrics = module.get_metrics(mobj.PERFDATA, mobj) + + for pair in carbon_metrics: + nobj = copy.copy(mobj) + nobj.PATH = pair[0] + nobj.VALUE = pair[1] + processed_objects.append(nobj) + + continue + for metric in mobj.PERFDATA.split(): try: nobj = copy.copy(mobj) @@ -364,6 +392,29 @@ def process_log(file_name): return processed_objects +def try_load(path): + """ + return the module given by path, load if not loaded + """ + base, name = os.path.split(path) + name, ext = os.path.splitext(name) + + # Return module if already loaded + try: + return sys.modules[name] + except KeyError: + pass + + try: + return imp.load_source(name, path) + except (IOError, OSError, Exception) as e: + print "Exception occured while loading plugin path %s:" % path + print " %s" % e + print "Check the path, or file permissions." + print "Exiting." + exit(1) + + def get_mobj(nag_array): """ takes a split array of nagios variables and returns a mobj if it's @@ -378,14 +429,18 @@ def get_mobj(nag_array): log.warn("could not split value %s, dropping metric" % var) return False - value = re.sub("/", cfg["replacement_character"], value) + replaced = re.sub("/", cfg["replacement_character"], value) + if re.search("PERFDATA", var_name): - mobj.PERFDATA = value - elif re.search("^\$_", value): + mobj.PERFDATA = replaced + elif re.search("^\$_", replaced): continue - else: - value = re.sub("\s", "", value) + elif cfg['override_with_plugin']: setattr(mobj, var_name, value) + else: + replaced = re.sub("\s", "", replaced) + setattr(mobj, var_name, replaced) + mobj.validate() if mobj.VALID is True: return mobj diff --git a/graphios_backends.py b/graphios_backends.py index 81e976a..83da6ea 100644 --- a/graphios_backends.py +++ b/graphios_backends.py @@ -274,6 +274,13 @@ def __init__(self, cfg): except: self.carbon_plaintext = False + try: + if cfg['override_with_plugin']: + self.plugin_path = cfg['plugin_path'] + self.override_with_plugin = cfg['override_with_plugin'] + except: + self.override_with_plugin = False + def convert_messages(self, metrics): """ Converts the metric obj list into graphite messages @@ -312,17 +319,19 @@ def build_path(self, m): """ Builds a carbon metric """ - if m.GRAPHITEPREFIX != "": + if self.override_with_plugin: + return m.PATH + + path = "" + pre = "" + post = "" + + if m.GRAPHITEPREFIX: pre = "%s." % m.GRAPHITEPREFIX - else: - pre = "" - if m.GRAPHITEPOSTFIX != "": + + if m.GRAPHITEPOSTFIX: post = ".%s" % m.GRAPHITEPOSTFIX - else: - post = "" - # if self.replace_hostname: - # hostname = m.HOSTNAME.replace('.', self.replacement_character) - # else: + hostname = m.HOSTNAME if self.use_service_desc: # we want: (prefix.)hostname.service_desc(.postfix).perfdata @@ -331,6 +340,7 @@ def build_path(self, m): m.LABEL) else: path = "%s%s%s.%s" % (pre, hostname, post, m.LABEL) + path = re.sub(r"\.$", '', path) # fix paths that end in dot path = re.sub(r"\.\.", '.', path) # fix paths with double dots path = self.fix_string(path) diff --git a/nagios/nagios_perfdata.cfg b/nagios/nagios_perfdata.cfg index 35c47ae..7325242 100644 --- a/nagios/nagios_perfdata.cfg +++ b/nagios/nagios_perfdata.cfg @@ -2,12 +2,12 @@ ###### Auto-generated Graphios configs ####### process_performance_data=1 service_perfdata_file=/var/spool/nagios/graphios/service-perfdata -service_perfdata_file_template=DATATYPE::SERVICEPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tSERVICEDESC::$SERVICEDESC$\tSERVICEPERFDATA::$SERVICEPERFDATA$\tSERVICECHECKCOMMAND::$SERVICECHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tSERVICESTATE::$SERVICESTATE$\tSERVICESTATETYPE::$SERVICESTATETYPE$\tGRAPHITEPREFIX::$_SERVICEGRAPHITEPREFIX$\tGRAPHITEPOSTFIX::$_SERVICEGRAPHITEPOSTFIX$\tMETRICTYPE::$_SERVICEMETRICTYPE$ +service_perfdata_file_template=DATATYPE::SERVICEPERFDATA\tSERVICEOUTPUT::$SERVICEOUTPUT$\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tSERVICEDESC::$SERVICEDESC$\tSERVICEPERFDATA::$SERVICEPERFDATA$\tSERVICECHECKCOMMAND::$SERVICECHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tSERVICESTATE::$SERVICESTATE$\tSERVICESTATETYPE::$SERVICESTATETYPE$\tGRAPHITEPREFIX::$_SERVICEGRAPHITEPREFIX$\tGRAPHITEPOSTFIX::$_SERVICEGRAPHITEPOSTFIX$\tMETRICTYPE::$_SERVICEMETRICTYPE$ service_perfdata_file_mode=a service_perfdata_file_processing_interval=15 service_perfdata_file_processing_command=graphios_perf_service host_perfdata_file=/var/spool/nagios/graphios/host-perfdata -host_perfdata_file_template=DATATYPE::HOSTPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tHOSTPERFDATA::$HOSTPERFDATA$\tHOSTCHECKCOMMAND::$HOSTCHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tGRAPHITEPREFIX::$_HOSTGRAPHITEPREFIX$\tGRAPHITEPOSTFIX::$_HOSTGRAPHITEPOSTFIX$\tMETRICTYPE::$_HOSTMETRICTYPE$ +host_perfdata_file_template=\tDATATYPE::HOSTPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tHOSTPERFDATA::$HOSTPERFDATA$\tHOSTCHECKCOMMAND::$HOSTCHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tGRAPHITEPREFIX::$_HOSTGRAPHITEPREFIX$\tGRAPHITEPOSTFIX::$_HOSTGRAPHITEPOSTFIX$\tMETRICTYPE::$_HOSTMETRICTYPE$ host_perfdata_file_mode=a host_perfdata_file_processing_interval=15 host_perfdata_file_processing_command=graphios_perf_host diff --git a/plugins/plugin_example.py b/plugins/plugin_example.py new file mode 100644 index 0000000..1dd8df7 --- /dev/null +++ b/plugins/plugin_example.py @@ -0,0 +1,35 @@ +# This is a sample plugin used for flexible reporting of metrics +# +# Graphios makes the call `get_metrics(perfdata, nag)` where +# +# nag: contains all the fields defined in the nagios log +# perfdata: is just nag.PERFDATA +# +# It expects the output to be a list of metric paths and values and +# Graphios will use the nag.TIMET timestamp to form the correct metric +# +# For example: +# +# get_metrics() -> [ ( "stats.server1.cpu", .10 ) ] +# +# Would result in the following metric: +# +# stats.server1.cpu .10 +# +# Graphios will append the timestamp, only the path, and value pair must be +# returned +# + +def get_metrics(perfdata, nag): + """ + returns a [(, )] where each is the metric to send to carbon + """ + + results = [] + for metric in perfdata.split(): + label = perfdata.split('=')[0] + path = "%s.%s.%s" % (nag.GRAPHITEPREFIX, nag.HOSTNAME, label) + value = nag.VALUE + results.append((path, value)) + + return results diff --git a/setup.py b/setup.py index 9b2edb1..aa7aa12 100644 --- a/setup.py +++ b/setup.py @@ -91,8 +91,8 @@ def _post_install(): """ tries to find the nagios.cfg and insert graphios perf commands/cfg """ - lookin = ['/etc/nagios/', '/opt/nagios/', '/usr/local/nagios', - '/usr/nagios'] + lookin = ['/etc/nagios3/', '/etc/nagios/', '/opt/nagios/', + '/usr/local/nagios', '/usr/nagios'] nag_cfg = find_nagios_cfg(lookin) if nag_cfg is None: print("sorry I couldn't find the nagios.cfg file")