Skip to content
Snippets Groups Projects
Commit f7248f2d authored by jurgenhaas's avatar jurgenhaas
Browse files

Improved version of haproxy charts

parent fc66bc93
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,7 @@
# Description: haproxy netdata python.d module
# Author: l2isbad
from base import UrlService
from base import UrlService, SocketService
# default module values (can be overridden per job in `config`)
# update_every = 2
......@@ -10,14 +10,14 @@ priority = 60000
retries = 60
# charts order (can be overridden if you want less charts, or different order)
ORDER = ['fbin', 'fbout', 'fscur', 'fqcur', 'bbin', 'bbout', 'bscur', 'bqcur']
ORDER = ['fbin', 'fbout', 'fscur', 'fqcur', 'bbin', 'bbout', 'bscur', 'bqcur', 'health_down']
CHARTS = {
'fbin': {
'options': [None, "Bytes in", "bytes/s", 'Frontend', 'f.bin', 'line'],
'options': [None, "Kilobytes in", "kilobytes in/s", 'Frontend', 'f.bin', 'line'],
'lines': [
]},
'fbout': {
'options': [None, "Bytes out", "bytes/s", 'Frontend', 'f.bout', 'line'],
'options': [None, "Kilobytes out", "kilobytes out/s", 'Frontend', 'f.bout', 'line'],
'lines': [
]},
'fscur': {
......@@ -29,11 +29,11 @@ CHARTS = {
'lines': [
]},
'bbin': {
'options': [None, "Bytes in", "bytes/s", 'Backend', 'b.bin', 'line'],
'options': [None, "Kilobytes in", "kilobytes in/s", 'Backend', 'b.bin', 'line'],
'lines': [
]},
'bbout': {
'options': [None, "Bytes out", "bytes/s", 'Backend', 'b.bout', 'line'],
'options': [None, "Kilobytes out", "kilobytes out/s", 'Backend', 'b.bout', 'line'],
'lines': [
]},
'bscur': {
......@@ -43,55 +43,74 @@ CHARTS = {
'bqcur': {
'options': [None, "Sessions in queue", "sessions", 'Backend', 'b.qcur', 'line'],
'lines': [
]},
'health_down': {
'options': [None, "Servers in DOWN state", "failed servers", 'Health', 'h.down', 'line'],
'lines': [
]}
}
class Service(UrlService):
class Service(UrlService, SocketService):
def __init__(self, configuration=None, name=None):
UrlService.__init__(self, configuration=configuration, name=name)
self.url = "http://127.0.0.1:7000/haproxy_stats;csv"
SocketService.__init__(self, configuration=configuration, name=name)
self.user = self.configuration.get('user')
self.password = self.configuration.get('pass')
self.request = 'show stat\n'
self.poll_method = (UrlService, SocketService)
self.order = ORDER
self.order_front = [_ for _ in ORDER if _.startswith('f')]
self.order_back = [_ for _ in ORDER if _.startswith('b')]
self.definitions = CHARTS
self.charts = True
def check(self):
if self.configuration.get('url'):
self.poll_method = self.poll_method[0]
url = self.configuration.get('url')
if not url.endswith(';csv;norefresh'):
self.error('Bad url(%s). Must be http://<ip.address>:<port>/<url>;csv;norefresh' % url)
return False
elif self.configuration.get('socket'):
self.poll_method = self.poll_method[1]
else:
self.error('No configuration is specified')
return False
if self.poll_method.check(self):
self.info('Plugin was started succesfully. We are using %s.' % self.poll_method.__name__)
return True
def create_charts(self, front_ends, back_ends):
for chart in self.order_front:
for _ in range(len(front_ends)):
self.definitions[chart]['lines'].append(['_'.join([chart, front_ends[_]['# pxname']]),
front_ends[_]['# pxname'],
'incremental' if chart.startswith(
('fb', 'bb')) else 'absolute'])
for chart in self.order_back:
for _ in range(len(back_ends)):
self.definitions[chart]['lines'].append(['_'.join([chart, back_ends[_]['# pxname']]),
back_ends[_]['# pxname'],
'incremental' if chart.startswith(
('fb', 'bb')) else 'absolute'])
for _ in range(len(front_ends)):
self.definitions['fbin']['lines'].append(['_'.join(['fbin', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'incremental', 1, 1024])
self.definitions['fbout']['lines'].append(['_'.join(['fbout', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'incremental', 1, 1024])
self.definitions['fscur']['lines'].append(['_'.join(['fscur', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'absolute'])
self.definitions['fqcur']['lines'].append(['_'.join(['fqcur', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'absolute'])
for _ in range(len(back_ends)):
self.definitions['bbin']['lines'].append(['_'.join(['bbin', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'incremental', 1, 1024])
self.definitions['bbout']['lines'].append(['_'.join(['bbout', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'incremental', 1, 1024])
self.definitions['bscur']['lines'].append(['_'.join(['bscur', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
self.definitions['bqcur']['lines'].append(['_'.join(['bqcur', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
self.definitions['health_down']['lines'].append(['_'.join(['hdown', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
def _get_data(self):
"""
Format data received from http request
:return: dict
"""
if self.url[-4:] != ';csv':
self.url += ';csv'
self.info('Url rewritten to %s' % self.url)
try:
raw_data = self._get_raw_data().splitlines()
raw_data = self.poll_method._get_raw_data(self).splitlines()
except Exception as e:
self.error(str(e))
return None
all_instances = [dict(zip(raw_data[0].split(','), raw_data[_].split(','))) for _ in range(1, len(raw_data))]
back_ends = [backend for backend in all_instances
if backend['svname'] == 'BACKEND' and backend['# pxname'] != 'stats']
front_ends = [frontend for frontend in all_instances
if frontend['svname'] == 'FRONTEND' and frontend['# pxname'] != 'stats']
back_ends = list(filter(is_backend, all_instances))
front_ends = list(filter(is_frontend, all_instances))
servers = list(filter(is_server, all_instances))
if self.charts:
self.create_charts(front_ends, back_ends)
......@@ -107,4 +126,40 @@ class Service(UrlService):
for _ in self.order_back:
to_netdata.update({'_'.join([_, backend['# pxname']]): int(backend[_[1:]]) if backend.get(_[1:]) else 0})
for _ in range(len(back_ends)):
to_netdata.update({'_'.join(['hdown', back_ends[_]['# pxname']]):
len([server for server in servers if is_server_down(server, back_ends, _)])})
return to_netdata
def _check_raw_data(self, data):
"""
Check if all data has been gathered from socket
:param data: str
:return: boolean
"""
return not bool(data)
def is_backend(backend):
try:
return backend['svname'] == 'BACKEND' and backend['# pxname'] != 'stats'
except Exception:
return False
def is_frontend(frontend):
try:
return frontend['svname'] == 'FRONTEND' and frontend['# pxname'] != 'stats'
except Exception:
return False
def is_server(server):
try:
return not server['svname'].startswith(('FRONTEND', 'BACKEND'))
except Exception:
return False
def is_server_down(server, back_ends, _):
try:
return server['# pxname'] == back_ends[_]['# pxname'] and server['status'] != 'UP'
except Exception:
return False
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment