summaryrefslogtreecommitdiffstats
path: root/python.d
diff options
context:
space:
mode:
Diffstat (limited to 'python.d')
-rw-r--r--python.d/Makefile.am1
-rw-r--r--python.d/Makefile.in13
-rw-r--r--python.d/README.md11
-rw-r--r--python.d/hddtemp.chart.py5
-rw-r--r--python.d/mysql.chart.py33
-rwxr-xr-xpython.d/phpfpm.chart.py59
-rw-r--r--python.d/python_modules/base.py2
-rw-r--r--python.d/retroshare.chart.py78
-rw-r--r--python.d/sensors.chart.py29
9 files changed, 186 insertions, 45 deletions
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: