From 1e7e66c71f5bfcc1d57aa788dd8cedc4b14d46a5 Mon Sep 17 00:00:00 2001 From: Markus Opolka Date: Tue, 28 Apr 2026 11:45:21 +0200 Subject: [PATCH] Add -M flag to map non-numeric perfdata values --- README.md | 29 ++++++++++++++++++++++++++--- check_http_json.py | 26 +++++++++++++++++++++++--- test/test_args.py | 4 ++++ test/test_check_http_json.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index de1b2a2..0f6be4e 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ usage: check_http_json.py [-h] [-d] [-s] -H HOST [-k] [-V] [--cacert CACERT] [-y [KEY_VALUE_LIST_NOT [KEY_VALUE_LIST_NOT ...]]] [-Y [KEY_VALUE_LIST_NOT_CRITICAL [KEY_VALUE_LIST_NOT_CRITICAL ...]]] [-m [METRIC_LIST [METRIC_LIST ...]]] + [-M KEY=VALUE] Check HTTP JSON Nagios Plugin @@ -73,8 +74,6 @@ Generic Nagios plugin which checks json values from a given endpoint against argument specified rules and determines the status and performance data for that service. -Version: 2.2.0 (2024-05-14) - options: -h, --help show this help message and exit -d, --debug debug mode @@ -125,7 +124,7 @@ options: (key[>alias],value key2,value2) to determine status. Multiple key values can be delimited with colon (key,value1:value2). Return warning if the key is older - than the value (ex.: 30s,10m,2h,3d,...). + than the value (ex.: 30s,10m,2h,3d,...). With at it return warning if the key is jounger than the value (ex.: @30s,@10m,@2h,@3d,...). With Minus you can shift the time in the future. @@ -144,6 +143,8 @@ options: performance data. More information about Range format and units of measure for nagios can be found at nagios- plugins.org/doc/guidelines.html Additional formats for this parameter are: (key[>alias]), (key[>alias],UnitOfMeasure), (key[>alias],UnitOfMeasure,WarnRange, CriticalRange). + -M KEY=VALUE Map the values of the gathered metric to the given values. This can be used to map non-numeric values to numeric values, e.g. -M + Up=1. Can used multiple times. This flag is meant to be used with the -m flag. ``` The check plugin respects the environment variables `HTTP_PROXY`, `HTTPS_PROXY`. @@ -255,6 +256,28 @@ The check plugin respects the environment variables `HTTP_PROXY`, `HTTPS_PROXY`. More info about Nagios Range format and Units of Measure can be found at [https://nagios-plugins.org/doc/guidelines.html](https://nagios-plugins.org/doc/guidelines.html). +### Performance Data Metrics + +The `-m` and `-M` flags can be used to generate performance data from the JSON data. + +``` +check_http_json.py -H host.internal --path example-data.json -e 'service.requests' -m 'service.requests' +OK: 'service.requests'=12 Status OK. |'service.requests'=12 + +check_http_json.py -H host.internal --path example-data.json -e 'service.requests' -m 'service.requests>webshopRequests,c' +OK: 'webshopRequests'=12c Status OK. |'webshopRequests'=12c +``` + +The `-M` flag can be used to map non-numeric values to numeric values. + +``` +check_http_json.py -H host.internal --path example-data.json -e 'service.status' -m 'service.status' +OK: 'service.status'=Up Status OK. |'service.requests'=Up + +check_http_json.py -H host.internal --path example-data.json -e 'service.status' -m 'service.status' -M Up=1 +OK: 'service.status'=1 Status OK. |'service.requests'=1 +``` + ### Timestamp **Data**: diff --git a/check_http_json.py b/check_http_json.py index 6d13713..6e510eb 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -441,10 +441,12 @@ def checkMetrics(self): Return a Nagios specific performance metrics string given keys and parameter definitions """ - metrics = '' warning = '' critical = '' + + kv = dict(self.rules.metric_value_mapping) if hasattr(self.rules, 'metric_value_mapping') else {} + if self.metric_list is not None: for metric in self.metric_list: key = metric @@ -461,7 +463,10 @@ def checkMetrics(self): minimum, maximum = vals key, alias = _getKeyAlias(key) if self.helper.exists(key): - metrics += "'%s'=%s" % (alias, self.helper.get(key)) + value = self.helper.get(key) + # Apply the value mapping if it exists + v = kv.get(str(value), value) + metrics += "'%s'=%s" % (alias, v) if uom: metrics += uom if warn_range is not None: @@ -481,7 +486,6 @@ def checkMetrics(self): metrics += ' ' return ("%s" % metrics, warning, critical) - def parseArgs(args): """ CLI argument definitions and parsing @@ -608,10 +612,26 @@ def parseArgs(args): (key[>alias]), (key[>alias],UnitOfMeasure), (key[>alias],UnitOfMeasure,WarnRange, CriticalRange).''') + parser.add_argument('-M', dest='metric_value_mapping', metavar="KEY=VALUE", + type=key_value_pair, + action="append", + default=[], + help='''Map the values of the gathered metric to the given values. + This can be used to map non-numeric values to numeric values, e.g. -M Up=1. Can used multiple times. + This flag is meant to be used with the -m flag.''') return parser.parse_args(args) +def key_value_pair(value): + """ + Small helper to split key=value arguments into a tuple. + """ + parts = value.split('=', 1) + if len(parts) != 2: + raise argparse.ArgumentTypeError('invalid format %s. Expected key=value' % (value)) + return (parts[0], parts[1]) + def debugPrint(debug_flag, message): """ Print debug messages if -d is set. diff --git a/test/test_args.py b/test/test_args.py index cecd9b4..53639f8 100644 --- a/test/test_args.py +++ b/test/test_args.py @@ -32,3 +32,7 @@ def test_parser_with_separator(self): parser = parseArgs(['-H', 'foobar', '-f', '_', '-F', '_']) self.assertEqual(parser.separator, '_') self.assertEqual(parser.value_separator, '_') + + def test_parser_with_value_mapping(self): + parser = parseArgs(['-H', 'foobar', '-M', 'key=value']) + self.assertEqual(parser.metric_value_mapping, [('key', 'value')]) diff --git a/test/test_check_http_json.py b/test/test_check_http_json.py index 33627e3..837f014 100644 --- a/test/test_check_http_json.py +++ b/test/test_check_http_json.py @@ -234,6 +234,40 @@ def test_critical_thresholds(self): self.check_data(RulesHelper().dash_c(['(*).value,@1:5']), '[{"value": 5},{"value": 1000}]', CRITICAL_CODE) + def test_metrics_value_mapping(self): + data = json.loads('{"status": "Up"}') + expected = ("'status'=0 ", '', '') + + processor = JsonRuleProcessor(data, parseArgs(['-H', 'foobar', '-m', 'status', '-M', 'Up=0'])) + actual = processor.checkMetrics() + + self.assertEqual(actual, expected) + + data = json.loads('{"status": "Down"}') + expected = ("'status'=1 ", '', '') + + processor = JsonRuleProcessor(data, parseArgs(['-H', 'foobar', '-m', 'status', '-M', 'Up=0', '-M', 'Down=1'])) + actual = processor.checkMetrics() + + self.assertEqual(actual, expected) + + def test_metrics_value_mapping_datatypes(self): + data = json.loads('{"status": "123"}') + expected = ("'status'=foo ", '', '') + # Test with string value as target + processor = JsonRuleProcessor(data, parseArgs(['-H', 'foobar', '-m', 'status', '-M', '123=foo'])) + actual = processor.checkMetrics() + + self.assertEqual(actual, expected) + + data = json.loads('{"status": 123}') + expected = ("'status'=foo ", '', '') + # Test with string value as source and target + processor = JsonRuleProcessor(data, parseArgs(['-H', 'foobar', '-m', 'status', '-M', '123=foo'])) + actual = processor.checkMetrics() + + self.assertEqual(actual, expected) + def test_separator(self): rules = RulesHelper() rules.separator = '_'