From 87649cf32bd0e14d5a903fb85b01e9f41a253540 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Wed, 23 Nov 2016 15:49:10 +0000 Subject: New upstream version 1.4.0+dfsg --- python.d/Makefile.am | 1 + python.d/Makefile.in | 13 +++++-- python.d/README.md | 11 +++--- python.d/hddtemp.chart.py | 5 ++- python.d/mysql.chart.py | 33 ++++++----------- python.d/phpfpm.chart.py | 59 ++++++++++++++++++++++++++++--- python.d/python_modules/base.py | 2 ++ python.d/retroshare.chart.py | 78 +++++++++++++++++++++++++++++++++++++++++ python.d/sensors.chart.py | 29 +++++++++------ 9 files changed, 186 insertions(+), 45 deletions(-) create mode 100644 python.d/retroshare.chart.py (limited to 'python.d') diff --git a/python.d/Makefile.am b/python.d/Makefile.am index 8bccba378..d769e3138 100644 --- a/python.d/Makefile.am +++ b/python.d/Makefile.am @@ -23,6 +23,7 @@ dist_python_SCRIPTS = \ phpfpm.chart.py \ postfix.chart.py \ redis.chart.py \ + retroshare.chart.py \ sensors.chart.py \ squid.chart.py \ tomcat.chart.py \ diff --git a/python.d/Makefile.in b/python.d/Makefile.in index 0e1925c56..426f43ed1 100644 --- a/python.d/Makefile.in +++ b/python.d/Makefile.in @@ -85,8 +85,13 @@ DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \ $(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA) subdir = python.d ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \ - $(top_srcdir)/configure.ac +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \ + $(top_srcdir)/m4/ax_c__generic.m4 \ + $(top_srcdir)/m4/ax_c_mallinfo.m4 \ + $(top_srcdir)/m4/ax_c_mallopt.m4 \ + $(top_srcdir)/m4/ax_check_compile_flag.m4 \ + $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/jemalloc.m4 \ + $(top_srcdir)/m4/tcmalloc.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -213,6 +218,7 @@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ +SSE_CANDIDATE = @SSE_CANDIDATE@ STRIP = @STRIP@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ @@ -245,6 +251,8 @@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ +has_jemalloc = @has_jemalloc@ +has_tcmalloc = @has_tcmalloc@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -302,6 +310,7 @@ dist_python_SCRIPTS = \ phpfpm.chart.py \ postfix.chart.py \ redis.chart.py \ + retroshare.chart.py \ sensors.chart.py \ squid.chart.py \ tomcat.chart.py \ diff --git a/python.d/README.md b/python.d/README.md index 4cc4d8d2f..a3c7b4fac 100644 --- a/python.d/README.md +++ b/python.d/README.md @@ -48,7 +48,7 @@ This module will monitor one or more apache servers depending on configuration. **Requirements:** * apache with enabled `mod_status` -It produces following charts: +It produces the following charts: 1. **Requests** in requests/s * requests @@ -235,7 +235,7 @@ Configuration is not needed. # hddtemp -Module monitors disk temperatures from one or more hddtemp daemons +Module monitors disk temperatures from one or more hddtemp daemons. **Requirement:** Running `hddtemp` in daemonized mode with access on tcp port @@ -444,10 +444,13 @@ If no configuration is given, module will attempt to connect to mysql server via # nginx -This module will monitor one or more nginx servers depending on configuration. +This module will monitor one or more nginx servers depending on configuration. Servers can be either local or remote. **Requirements:** - * nginx with configured `stub_status` + * nginx with configured 'ngx_http_stub_status_module' + * 'location /stub_status' + +Example nginx configuration can be found in 'python.d/nginx.conf' It produces following charts: diff --git a/python.d/hddtemp.chart.py b/python.d/hddtemp.chart.py index 4271001b7..465bfdfa2 100644 --- a/python.d/hddtemp.chart.py +++ b/python.d/hddtemp.chart.py @@ -44,7 +44,7 @@ class Service(SocketService): def _get_disks(self): try: disks = self.configuration['devices'] - print(disks) + self.info("Using configured disks" + str(disks)) except (KeyError, TypeError) as e: self.info("Autodetecting disks") return ["/dev/" + f for f in os.listdir("/dev") if len(f) == 3 and f.startswith("sd")] @@ -53,8 +53,7 @@ class Service(SocketService): for disk in disks: if not disk.startswith('/dev/'): disk = "/dev/" + disk - if os.path.exists(disk): - ret.append(disk) + ret.append(disk) if len(ret) == 0: self.error("Provided disks cannot be found in /dev directory.") return ret diff --git a/python.d/mysql.chart.py b/python.d/mysql.chart.py index 7c3931acf..dab6fad3b 100644 --- a/python.d/mysql.chart.py +++ b/python.d/mysql.chart.py @@ -317,40 +317,29 @@ class Service(SimpleService): :param configuration: dict :return: dict """ + parameters = {} if self.name is None: self.name = 'local' - if 'user' not in configuration: - self.configuration['user'] = 'root' - if 'pass' not in configuration: - self.configuration['pass'] = '' + if 'user' in configuration: + parameters['user'] = self.configuration['user'] + if 'pass' in configuration: + parameters['passwd'] = self.configuration['pass'] if 'my.cnf' in configuration: - self.configuration['socket'] = '' - self.configuration['host'] = '' - self.configuration['port'] = 0 + parameters['read_default_file'] = self.configuration['my.cnf'] elif 'socket' in configuration: - self.configuration['my.cnf'] = '' - self.configuration['host'] = '' - self.configuration['port'] = 0 + parameters['unix_socket'] = self.configuration['socket'] elif 'host' in configuration: - self.configuration['my.cnf'] = '' - self.configuration['socket'] = '' + parameters['host'] = self.configuration['host'] if 'port' in configuration: - self.configuration['port'] = int(configuration['port']) - else: - self.configuration['port'] = 3306 + parameters['port'] = int(self.configuration['port']) + self.connection_parameters = parameters def _connect(self): """ Try to connect to MySQL server """ try: - self.connection = MySQLdb.connect(user=self.configuration['user'], - passwd=self.configuration['pass'], - read_default_file=self.configuration['my.cnf'], - unix_socket=self.configuration['socket'], - host=self.configuration['host'], - port=self.configuration['port'], - connect_timeout=self.update_every) + self.connection = MySQLdb.connect(connect_timeout=self.update_every, **self.connection_parameters) except MySQLdb.OperationalError as e: self.error("Cannot establish connection to MySQL.") self.debug(str(e)) diff --git a/python.d/phpfpm.chart.py b/python.d/phpfpm.chart.py index d1791d42e..d4168cc11 100755 --- a/python.d/phpfpm.chart.py +++ b/python.d/phpfpm.chart.py @@ -3,6 +3,7 @@ # Author: Pawel Krupa (paulfantom) from base import UrlService +import json # default module values (can be overridden per job in `config`) # update_every = 2 @@ -14,11 +15,11 @@ retries = 60 # 'update_every': update_every, # 'retries': retries, # 'priority': priority, -# 'url': 'http://localhost/status' +# 'url': 'http://localhost/status?full&json' # }} # charts order (can be overridden if you want less charts, or different order) -ORDER = ['connections', 'requests', 'performance'] +ORDER = ['connections', 'requests', 'performance', 'request_duration', 'request_cpu', 'request_mem'] CHARTS = { 'connections': { @@ -38,6 +39,24 @@ CHARTS = { 'lines': [ ["reached", 'max children reached'], ["slow", 'slow requests'] + ]}, + 'request_duration': { + 'options': [None, 'PHP-FPM Request Duration', 'milliseconds', 'phpfpm', 'phpfpm.request_duration', 'line'], + 'lines': [ + ["maxReqDur", 'max request duration'], + ["avgReqDur", 'average request duration'] + ]}, + 'request_cpu': { + 'options': [None, 'PHP-FPM Request CPU', 'percent', 'phpfpm', 'phpfpm.request_cpu', 'line'], + 'lines': [ + ["maxReqCPU", 'max request cpu'], + ["avgReqCPU", 'average request cpu'] + ]}, + 'request_mem': { + 'options': [None, 'PHP-FPM Request Memory', 'kilobytes', 'phpfpm', 'phpfpm.request_mem', 'line'], + 'lines': [ + ["maxReqMem", 'max request memory'], + ["avgReqMem", 'average request memory'] ]} } @@ -46,7 +65,7 @@ class Service(UrlService): def __init__(self, configuration=None, name=None): UrlService.__init__(self, configuration=configuration, name=name) if len(self.url) == 0: - self.url = "http://localhost/status" + self.url = "http://localhost/status?full&json" self.order = ORDER self.definitions = CHARTS self.assignment = {"active processes": 'active', @@ -55,6 +74,9 @@ class Service(UrlService): "accepted conn": 'requests', "max children reached": 'reached', "slow requests": 'slow'} + self.proc_assignment = {"request duration": 'ReqDur', + "last request cpu": 'ReqCPU', + "last request memory": 'ReqMem'} def _get_data(self): """ @@ -62,9 +84,38 @@ class Service(UrlService): :return: dict """ try: - raw = self._get_raw_data().split('\n') + raw = self._get_raw_data() except AttributeError: return None + + if '?json' in self.url or '&json' in self.url: + try: + raw_json = json.loads(raw) + except ValueError: + return None + data = {self.assignment[k]: v for k, v in raw_json.items() if k in self.assignment} + if '&full' in self.url or '?full' in self.url: + c = 0 + for proc in raw_json['processes']: + if proc['state'] != 'Idle': + continue + c += 1 + for k, v in self.proc_assignment.items(): + d = proc[k] + if v == 'ReqDur': + d = d/1000 + if v == 'ReqMem': + d = d/1024 + if 'max' + v not in data or data['max' + v] < d: + data['max' + v] = d + if 'avg' + v not in data: + data['avg' + v] = 0 + data['avg' + v] = (data['avg' + v] + d) / c + if len(data) == 0: + return None + return data + + raw = raw.split('\n') data = {} for row in raw: tmp = row.split(":") diff --git a/python.d/python_modules/base.py b/python.d/python_modules/base.py index c2bbed2a5..1508e0965 100644 --- a/python.d/python_modules/base.py +++ b/python.d/python_modules/base.py @@ -658,6 +658,7 @@ class SocketService(SimpleService): self.unix_socket = str(self.configuration['socket']) except (KeyError, TypeError): self.debug("No unix socket specified. Trying TCP/IP socket.") + self.unix_socket = None try: self.host = str(self.configuration['host']) except (KeyError, TypeError): @@ -673,6 +674,7 @@ class SocketService(SimpleService): self.request = self.request.encode() def check(self): + self._parse_config() return SimpleService.check(self) diff --git a/python.d/retroshare.chart.py b/python.d/retroshare.chart.py new file mode 100644 index 000000000..0c97973f6 --- /dev/null +++ b/python.d/retroshare.chart.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Description: RetroShare netdata python.d module +# Authors: sehraf + +from base import UrlService +import json + +# default module values (can be overridden per job in `config`) +# update_every = 2 +priority = 60000 +retries = 60 + +# charts order (can be overridden if you want less charts, or different order) +ORDER = ['bandwidth', 'peers', 'dht'] + +CHARTS = { + 'bandwidth': { + 'options': [None, 'RetroShare Bandwidth', 'kB/s', 'RetroShare', 'retroshare.bandwidth', 'area'], + 'lines': [ + ['bandwidth_up_kb', 'Upload'], + ['bandwidth_down_kb', 'Download'] + ]}, + 'peers': { + 'options': [None, 'RetroShare Peers', 'peers', 'RetroShare', 'retroshare.peers', 'line'], + 'lines': [ + ['peers_all', 'All friends'], + ['peers_connected', 'Connected friends'] + ]}, + 'dht': { + 'options': [None, 'Retroshare DHT', 'peers', 'RetroShare', 'retroshare.dht', 'line'], + 'lines': [ + ['dht_size_all', 'DHT nodes estimated'], + ['dht_size_rs', 'RS nodes estimated'] + ]} +} + + +class Service(UrlService): + def __init__(self, configuration=None, name=None): + UrlService.__init__(self, configuration=configuration, name=name) + try: + self.baseurl = str(self.configuration['url']) + except (KeyError, TypeError): + self.baseurl = 'http://localhost:9090' + self.order = ORDER + self.definitions = CHARTS + + def _get_stats(self): + """ + Format data received from http request + :return: dict + """ + try: + raw = self._get_raw_data() + parsed = json.loads(raw) + if str(parsed['returncode']) != 'ok': + return None + except: + return None + + return parsed['data'][0] + + def _get_data(self): + """ + Get data from API + :return: dict + """ + self.url = self.baseurl + '/api/v2/stats' + data = self._get_stats() + if data is None: + return None + + data['bandwidth_up_kb'] = data['bandwidth_up_kb'] * -1 + if data['dht_active'] is False: + data['dht_size_all'] = None + data['dht_size_rs'] = None + + return data diff --git a/python.d/sensors.chart.py b/python.d/sensors.chart.py index 7abe7f080..23bccb97c 100644 --- a/python.d/sensors.chart.py +++ b/python.d/sensors.chart.py @@ -49,6 +49,13 @@ CHARTS = { ]} } +LIMITS = { + 'temperature': [-127, 1000], + 'voltage': [-127, 127], + 'current': [-127, 127], + 'fan': [0, 65535] +} + TYPE_MAP = { 0: 'voltage', 1: 'fan', @@ -82,6 +89,11 @@ class Service(SimpleService): for sf in sfi: val = sensors.get_value(chip, sf.number) break + typeName = TYPE_MAP[feature.type] + if typeName in LIMITS: + limit = LIMITS[typeName]; + if val < limit[0] or val > limit[1]: + continue data[prefix + "_" + str(feature.name.decode())] = int(val * 1000) except Exception as e: self.error(e) @@ -92,7 +104,6 @@ class Service(SimpleService): return data def _create_definitions(self): - prev_chip = "" for type in ORDER: for chip in sensors.ChipIterator(): chip_name = sensors.chip_snprintf_name(chip) @@ -105,19 +116,17 @@ class Service(SimpleService): continue if TYPE_MAP[feature.type] == type: # create chart - if chip_name != prev_chip: - name = chip_name + "_" + TYPE_MAP[feature.type] - if name not in self.order: - self.order.append(name) - chart_def = list(CHARTS[type]['options']) - chart_def[1] = chip_name + chart_def[1] - self.definitions[name] = {'options': chart_def} - self.definitions[name]['lines'] = [] + name = chip_name + "_" + TYPE_MAP[feature.type] + if name not in self.order: + self.order.append(name) + chart_def = list(CHARTS[type]['options']) + chart_def[1] = chip_name + chart_def[1] + self.definitions[name] = {'options': chart_def} + self.definitions[name]['lines'] = [] line = list(CHARTS[type]['lines'][0]) line[0] = chip_name + "_" + str(feature.name.decode()) line[1] = sensors.get_label(chip, feature) self.definitions[name]['lines'].append(line) - prev_chip = chip_name def check(self): try: -- cgit v1.2.3