From fd951e0988d23bc602dc719ab4a01609b8ec0432 Mon Sep 17 00:00:00 2001 From: Walter Erquinigo Date: Mon, 14 Sep 2015 17:00:12 -0700 Subject: [PATCH 1/2] [haproxy] Count available/unavaiable backends and frontends The count_per_status currently counts both backends and frontends. An important query is how many backends are available or unavailable disregarding the big set of tags, which causes the typeaheads in the datadog ui to never load. In order to achieve this, a new counter 'haproxy.backend_hosts' is added. It has two tags: service and available. The latter is either true or false. --- checks.d/haproxy.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/checks.d/haproxy.py b/checks.d/haproxy.py index 6a1182d85f..983d34d26b 100644 --- a/checks.d/haproxy.py +++ b/checks.d/haproxy.py @@ -176,6 +176,11 @@ def _process_data(self, data, collect_aggregates_only, process_events, url=None, services_incl_filter=services_incl_filter, services_excl_filter=services_excl_filter ) + self._process_backend_hosts_metric( + self.hosts_statuses, + services_incl_filter=services_incl_filter, + services_excl_filter=services_excl_filter + ) return data @@ -247,6 +252,34 @@ def _tag_match_patterns(self, tag, filters): return True return False + def _process_backend_hosts_metric(self, hosts_statuses, services_incl_filter=None, + services_excl_filter=None): + agg_statuses = defaultdict(lambda: {'available': 0, 'unavailable': 0}) + for host_status, count in hosts_statuses.iteritems(): + try: + service, hostname, status = host_status + except Exception: + service, status = host_status + + if self._is_service_excl_filtered(service, services_incl_filter, services_excl_filter): + continue + status = status.lower() + if 'up' in status: + agg_statuses[service]['available'] += count + elif 'down' in status or 'maint' in status or 'nolb' in status: + agg_statuses[service]['unavailable'] += count + + for service in agg_statuses: + tags = ['service:%s' % service] + self.gauge( + 'haproxy.backend_hosts', + agg_statuses[service]['available'], + tags=tags + ['available:true']) + self.gauge( + 'haproxy.backend_hosts', + agg_statuses[service]['unavailable'], + tags=tags + ['available:false']) + def _process_status_metric(self, hosts_statuses, collect_status_metrics_by_host, services_incl_filter=None, services_excl_filter=None): agg_statuses = defaultdict(lambda: {'available': 0, 'unavailable': 0}) From 6c7019e110cf478445c8428622b0524f9bba5745 Mon Sep 17 00:00:00 2001 From: Walter Erquinigo Date: Thu, 17 Sep 2015 10:59:29 -0700 Subject: [PATCH 2/2] [haproxy] Add tests for backend_hosts --- checks.d/haproxy.py | 4 ++++ tests/checks/integration/test_haproxy.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/checks.d/haproxy.py b/checks.d/haproxy.py index 983d34d26b..5ca3ed8ba9 100644 --- a/checks.d/haproxy.py +++ b/checks.d/haproxy.py @@ -268,6 +268,9 @@ def _process_backend_hosts_metric(self, hosts_statuses, services_incl_filter=Non agg_statuses[service]['available'] += count elif 'down' in status or 'maint' in status or 'nolb' in status: agg_statuses[service]['unavailable'] += count + else: + # create the entries for this service anyway + agg_statuses[service] for service in agg_statuses: tags = ['service:%s' % service] @@ -279,6 +282,7 @@ def _process_backend_hosts_metric(self, hosts_statuses, services_incl_filter=Non 'haproxy.backend_hosts', agg_statuses[service]['unavailable'], tags=tags + ['available:false']) + return agg_statuses def _process_status_metric(self, hosts_statuses, collect_status_metrics_by_host, services_incl_filter=None, services_excl_filter=None): diff --git a/tests/checks/integration/test_haproxy.py b/tests/checks/integration/test_haproxy.py index a834c37530..17c09df3eb 100644 --- a/tests/checks/integration/test_haproxy.py +++ b/tests/checks/integration/test_haproxy.py @@ -219,6 +219,8 @@ def test_count_per_statuses(self): b,i-1,0,0,0,1,,1,1,0,,0,,0,0,0,0,UP,1,1,0,0,1,1,30,,1,3,1,,70,,2,0,,1,1,,0,,,,,,,0,,,,0,0, b,i-2,0,0,1,1,,1,1,0,,0,,0,0,0,0,UP,1,1,0,0,0,1,0,,1,3,2,,71,,2,0,,1,1,,0,,,,,,,0,,,,0,0, b,i-3,0,0,0,1,,1,1,0,,0,,0,0,0,0,UP,1,1,0,0,0,1,0,,1,3,3,,70,,2,0,,1,1,,0,,,,,,,0,,,,0,0, +b,i-4,0,0,0,1,,1,1,0,,0,,0,0,0,0,DOWN,1,1,0,0,0,1,0,,1,3,3,,70,,2,0,,1,1,,0,,,,,,,0,,,,0,0, +b,i-5,0,0,0,1,,1,1,0,,0,,0,0,0,0,MAINT,1,1,0,0,0,1,0,,1,3,3,,70,,2,0,,1,1,,0,,,,,,,0,,,,0,0, b,BACKEND,0,0,1,2,0,421,1,0,0,0,,0,0,0,0,UP,6,6,0,,0,1,0,,1,3,0,,421,,1,0,,1,,,,,,,,,,,,,,0,0, """.split('\n') @@ -229,9 +231,19 @@ def test_count_per_statuses(self): expected_hosts_statuses = defaultdict(int) expected_hosts_statuses[('b', 'OPEN')] = 1 expected_hosts_statuses[('b', 'UP')] = 3 + expected_hosts_statuses[('b', 'DOWN')] = 1 + expected_hosts_statuses[('b', 'MAINT')] = 1 expected_hosts_statuses[('a', 'OPEN')] = 1 self.assertEquals(self.check.hosts_statuses, expected_hosts_statuses) + # backend hosts + agg_statuses = self.check._process_backend_hosts_metric(expected_hosts_statuses) + expected_agg_statuses = { + 'a': {'available': 0, 'unavailable': 0}, + 'b': {'available': 3, 'unavailable': 2}, + } + self.assertEquals(expected_agg_statuses, dict(agg_statuses)) + # with collect_aggregates_only set to True self.check._process_data(data, True, True, collect_status_metrics=True, collect_status_metrics_by_host=False) @@ -246,6 +258,8 @@ def test_count_per_statuses(self): expected_hosts_statuses[('b', 'i-1', 'UP')] = 1 expected_hosts_statuses[('b', 'i-2', 'UP')] = 1 expected_hosts_statuses[('b', 'i-3', 'UP')] = 1 + expected_hosts_statuses[('b', 'i-4', 'DOWN')] = 1 + expected_hosts_statuses[('b', 'i-5', 'MAINT')] = 1 self.assertEquals(self.check.hosts_statuses, expected_hosts_statuses) self.check._process_data(data, True, True, collect_status_metrics=True,