]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #677 from paulfantom/master
authorCosta Tsaousis <costa@tsaousis.gr>
Wed, 13 Jul 2016 14:55:23 +0000 (17:55 +0300)
committerGitHub <noreply@github.com>
Wed, 13 Jul 2016 14:55:23 +0000 (17:55 +0300)
Redis python module + minor fixes

14 files changed:
charts.d/nginx.chart.sh
conf.d/Makefile.am
conf.d/python.d.conf
conf.d/python.d/exim.conf
conf.d/python.d/redis.conf [new file with mode: 0644]
plugins.d/python.d.plugin
python.d/Makefile.am
python.d/exim.chart.py
python.d/hddtemp.chart.py
python.d/python_modules/base.py
python.d/python_modules/msg.py
python.d/redis.chart.py [new file with mode: 0644]
python.d/squid.chart.py
web/index.html

index 9b75c2c5e68ae67ecf663b167e401ef470df22a2..a082c574e40fe5d945386458197d0e7eec1efdb9 100755 (executable)
@@ -82,18 +82,18 @@ nginx_check() {
 # _create is called once, to create the charts
 nginx_create() {
        cat <<EOF
-CHART nginx.connections '' "nginx Active Connections" "connections" nginx nginx.connections line $((nginx_priority + 1)) $nginx_update_every
+CHART nginx_local.connections '' "nginx Active Connections" "connections" nginx nginx.connections line $((nginx_priority + 1)) $nginx_update_every
 DIMENSION active '' absolute 1 1
 
-CHART nginx.requests '' "nginx Requests" "requests/s" nginx nginx.requests line $((nginx_priority + 2)) $nginx_update_every
+CHART nginx_local.requests '' "nginx Requests" "requests/s" nginx nginx.requests line $((nginx_priority + 2)) $nginx_update_every
 DIMENSION requests '' incremental 1 1
 
-CHART nginx.connections_status '' "nginx Active Connections by Status" "connections" nginx nginx.connections.status line $((nginx_priority + 3)) $nginx_update_every
+CHART nginx_local.connections_status '' "nginx Active Connections by Status" "connections" nginx nginx.connections.status line $((nginx_priority + 3)) $nginx_update_every
 DIMENSION reading '' absolute 1 1
 DIMENSION writing '' absolute 1 1
 DIMENSION waiting idle absolute 1 1
 
-CHART nginx.connect_rate '' "nginx Connections Rate" "connections/s" nginx nginx.connections.rate line $((nginx_priority + 4)) $nginx_update_every
+CHART nginx_local.connect_rate '' "nginx Connections Rate" "connections/s" nginx nginx.connections.rate line $((nginx_priority + 4)) $nginx_update_every
 DIMENSION accepts accepted incremental 1 1
 DIMENSION handled '' incremental 1 1
 EOF
@@ -114,18 +114,18 @@ nginx_update() {
 
        # write the result of the work.
        cat <<VALUESEOF
-BEGIN nginx.connections $1
+BEGIN nginx_local.connections $1
 SET active = $((nginx_active_connections))
 END
-BEGIN nginx.requests $1
+BEGIN nginx_local.requests $1
 SET requests = $((nginx_requests))
 END
-BEGIN nginx.connections_status $1
+BEGIN nginx_local.connections_status $1
 SET reading = $((nginx_reading))
 SET writing = $((nginx_writing))
 SET waiting = $((nginx_waiting))
 END
-BEGIN nginx.connect_rate $1
+BEGIN nginx_local.connect_rate $1
 SET accepts = $((nginx_accepts))
 SET handled = $((nginx_handled))
 END
index dd5d5102560fe300db099bfdd59f7ad67e06854c..20fc706230797f4e10f01e8967670b508fc683aa 100644 (file)
@@ -29,6 +29,7 @@ dist_pythonconfig_DATA = \
        python.d/nginx.conf \
        python.d/phpfpm.conf \
        python.d/postfix.conf \
+       python.d/redis.conf \
        python.d/sensors.conf \
        python.d/squid.conf \
        python.d/tomcat.conf \
index 195165634f9e90fe2206956d486ed37e5dcfde38..1fc66f423e59a5f47aaf98526981655a38c09d2a 100644 (file)
@@ -7,10 +7,16 @@ enabled: no
 # Modules can be disabled with setting "module_name = no"
 apache: yes
 apache_cache: yes
+cpufreq: yes
 example: yes
+exim: yes
 hddtemp: yes
 mysql: yes
 nginx: yes
 phpfpm: yes
+postfix: yes
+redis: yes
+sensors: yes
 squid: yes
+tomcat: yes
 
index 2c1317974746626c713855c30151f68658c9f812..0fefb8b954fa6ea1540e8b06f1feecf351b82f0c 100644 (file)
@@ -1,4 +1,4 @@
 # Example configuration of exim.chart.py
 # YAML format
 
-update_every : 2
+update_every : 8 # executing `exim -bpc` can be very slow
diff --git a/conf.d/python.d/redis.conf b/conf.d/python.d/redis.conf
new file mode 100644 (file)
index 0000000..7d8d294
--- /dev/null
@@ -0,0 +1,14 @@
+# Example configuration of redis.chart.py
+# YAML format
+
+update_every: 1
+retries: 10
+
+socket:
+  name     : 'local'
+  socket   : '/tmp/redis.sock'
+
+tcp:
+  name     : 'local'
+  host     : 'localhost'
+  port     : '6379'
\ No newline at end of file
index 741ba1f7378a28c8010633b00f9de4964fb0f592..d44721965c4a5f905639e5a3180425f55ab02bf0 100755 (executable)
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env bash
+'''':; exec "$(command -v python2 || command -v python3 || echo "ERROR python IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" # '''
 # -*- coding: utf-8 -*-
 
 # Description: netdata python modules supervisor
@@ -206,6 +207,8 @@ class PythonCharts(object):
         :param config: dict
         :return: dict
         """
+        if config is None:
+            config = {}
         # get default values
         defaults = {}
         msg.debug(module.__name__ + ": reading configuration")
@@ -280,11 +283,13 @@ class PythonCharts(object):
         :param reason: str
         """
         prefix = job.__module__
-        if job.name is not None:
+        if job.name is not None and len(job.name) != 0:
             prefix += "/" + job.name
         prefix += ": "
-
-        self.jobs.remove(job)
+        try:
+            self.jobs.remove(job)
+        except Exception as e:
+            msg.debug("This shouldn't happen. NO " + prefix + " IN LIST:" + str(self.jobs))
         if reason is None:
             return
         elif reason[:3] == "no ":
@@ -327,8 +332,8 @@ class PythonCharts(object):
                     try:
                         if job.override_name is not None:
                             job.name = job.override_name
-                            msg.debug(job.chart_name + " changing chart name to: " + job.__module__ + job.name)
-                            job.chart_name = job.__module__ + job.name
+                            msg.debug(job.chart_name + " changing chart name to: " + job.__module__ + '_' + job.name)
+                            job.chart_name = job.__module__ + '_' + job.name
                             overridden.append(job.name)
                     except Exception:
                         pass
@@ -421,7 +426,7 @@ def parse_cmdline(directory, *commands):
             DEBUG_FLAG = True
             # redirect stderr to stdout?
         elif os.path.isfile(directory + cmd + ".chart.py") or os.path.isfile(directory + cmd):
-            DEBUG_FLAG = True
+            #DEBUG_FLAG = True
             mods.append(cmd.replace(".chart.py", ""))
         else:
             try:
index 933b567139e8ddd54f10e25b0b17c9a5e62354e9..89a44b36a6e987e15ab30f8905bbee3bc1d571de 100644 (file)
@@ -18,6 +18,7 @@ dist_python_SCRIPTS = \
        nginx.chart.py \
        phpfpm.chart.py \
        postfix.chart.py \
+       redis.chart.py \
        sensors.chart.py \
        squid.chart.py \
        tomcat.chart.py \
index a267c2396edbdb18743f8aa34cf62d0a530c07d1..84981eadc37d021472aa0707737971e8c4b9a961 100644 (file)
@@ -34,8 +34,6 @@ class Service(ExecutableService):
         :return: dict
         """
         try:
-            raw = self._get_raw_data()[-1].split(' ')
-            return {'emails': raw[4],
-                    'size': raw[1]}
+            return {'emails': int(self._get_raw_data()[0])}
         except (ValueError, AttributeError):
             return None
index fac2ec6a167c93862d636922a732645cbdb6b79c..d0b53fc50d167b45821225a3bc20afdd0a0af4c0 100644 (file)
@@ -2,7 +2,7 @@
 # Description: hddtemp netdata python.d module
 # Author: Pawel Krupa (paulfantom)
 
-from base import NetSocketService
+from base import SocketService
 
 # default module values (can be overridden per job in `config`)
 #update_every = 2
@@ -29,9 +29,9 @@ CHARTS = {
 }
 
 
-class Service(NetSocketService):
+class Service(SocketService):
     def __init__(self, configuration=None, name=None):
-        NetSocketService.__init__(self, configuration=configuration, name=name)
+        SocketService.__init__(self, configuration=configuration, name=name)
         self.request = ""
         self.host = "127.0.0.1"
         self.port = 7634
index c2d5793801119c38d4d0eb0b0ae6c2b055f1f772..c10d795c9e4e764c87ec53afbf5f766a77fd2af0 100644 (file)
@@ -6,6 +6,7 @@ import time
 import sys
 import os
 import socket
+import resource
 try:
     import urllib.request as urllib2
 except ImportError:
@@ -93,27 +94,35 @@ class BaseService(threading.Thread):
         t_start = time.time()
         # check if it is time to execute job update() function
         if self.timetable['next'] > t_start:
-            msg.debug(self.chart_name + " will be run in " +
-                      str(int((self.timetable['next'] - t_start) * 1000)) + " ms")
+            #msg.debug(self.chart_name + " will be run in " +
+            #          str(int((self.timetable['next'] - t_start) * 1000)) + " ms")
+            msg.debug(self.chart_name,"will be run in", str(int((self.timetable['next'] - t_start) * 1000)), "ms")
             return True
 
         since_last = int((t_start - self.timetable['last']) * 1000000)
-        msg.debug(self.chart_name +
-                  " ready to run, after " + str(int((t_start - self.timetable['last']) * 1000)) +
-                  " ms (update_every: " + str(self.timetable['freq'] * 1000) +
-                  " ms, latency: " + str(int((t_start - self.timetable['next']) * 1000)) + " ms)")
+        #msg.debug(self.chart_name +
+        #          " ready to run, after " + str(int((t_start - self.timetable['last']) * 1000)) +
+        #          " ms (update_every: " + str(self.timetable['freq'] * 1000) +
+        #          " ms, latency: " + str(int((t_start - self.timetable['next']) * 1000)) + " ms)")
+        msg.debug(self.chart_name,
+                  "ready to run, after", str(int((t_start - self.timetable['last']) * 1000)),
+                  "ms (update_every:", str(self.timetable['freq'] * 1000),
+                  "ms, latency:", str(int((t_start - self.timetable['next']) * 1000)), "ms")
         if not self.update(since_last):
             return False
         t_end = time.time()
         self.timetable['next'] = t_end - (t_end % self.timetable['freq']) + self.timetable['freq']
-
         # draw performance graph
         run_time = str(int((t_end - t_start) * 1000))
-        run_time_chart = "BEGIN netdata.plugin_pythond_" + self.chart_name + " " + str(since_last) + '\n'
-        run_time_chart += "SET run_time = " + run_time + '\n'
-        run_time_chart += "END\n"
-        sys.stdout.write(run_time_chart)
-        msg.debug(self.chart_name + " updated in " + str(run_time) + " ms")
+        #run_time_chart = "BEGIN netdata.plugin_pythond_" + self.chart_name + " " + str(since_last) + '\n'
+        #run_time_chart += "SET run_time = " + run_time + '\n'
+        #run_time_chart += "END\n"
+        #sys.stdout.write(run_time_chart)
+        sys.stdout.write("BEGIN netdata.plugin_pythond_%s %s\nSET run_time = %s\nEND\n" % \
+                         (self.chart_name, str(since_last), run_time))
+
+        #msg.debug(self.chart_name + " updated in " + str(run_time) + " ms")
+        msg.debug(self.chart_name, "updated in", str(run_time), "ms")
         self.timetable['last'] = t_start
         return True
 
@@ -141,23 +150,42 @@ class BaseService(threading.Thread):
                 else:
                     time.sleep(self.timetable['freq'])
 
+    def _format(self, *args):
+        params = []
+        append = params.append
+        for p in args:
+            if p is None:
+                append(p)
+                continue
+            if type(p) is not str:
+                p = str(p)
+            if ' ' in p:
+                p = "'" + p + "'"
+            append(p)
+        return params
+
     def _line(self, instruction, *params):
         """
         Converts *params to string and joins them with one space between every one.
         :param params: str/int/float
         """
-        self._data_stream += instruction
-        for p in params:
-            if p is None:
-                p = ""
-            else:
-                p = str(p)
-            if len(p) == 0:
-                p = "''"
-            if ' ' in p:
-                p = "'" + p + "'"
-            self._data_stream += " " + p
-        self._data_stream += "\n"
+        #self._data_stream += instruction
+        tmp = list(map((lambda x: "''" if x is None or len(x) == 0 else x), params))
+
+        self._data_stream += "%s %s\n" % (instruction, str(" ".join(tmp)))
+
+        # self.error(str(" ".join(tmp)))
+        # for p in params:
+        #     if p is None:
+        #         p = ""
+        #     else:
+        #         p = str(p)
+        #     if len(p) == 0:
+        #         p = "''"
+        #     if ' ' in p:
+        #         p = "'" + p + "'"
+        #     self._data_stream += " " + p
+        #self._data_stream += "\n"
 
     def chart(self, type_id, name="", title="", units="", family="",
               category="", charttype="line", priority="", update_every=""):
@@ -174,7 +202,12 @@ class BaseService(threading.Thread):
         :param update_every: int/str
         """
         self._charts.append(type_id)
-        self._line("CHART", type_id, name, title, units, family, category, charttype, priority, update_every)
+        #self._line("CHART", type_id, name, title, units, family, category, charttype, priority, update_every)
+
+        p = self._format(type_id, name, title, units, family, category, charttype, priority, update_every)
+        self._line("CHART", *p)
+
+
 
     def dimension(self, id, name=None, algorithm="absolute", multiplier=1, divisor=1, hidden=False):
         """
@@ -204,9 +237,13 @@ class BaseService(threading.Thread):
 
         self._dimensions.append(id)
         if hidden:
-            self._line("DIMENSION", id, name, algorithm, multiplier, divisor, "hidden")
+            p = self._format(id, name, algorithm, multiplier, divisor, "hidden")
+            #self._line("DIMENSION", id, name, algorithm, str(multiplier), str(divisor), "hidden")
         else:
-            self._line("DIMENSION", id, name, algorithm, multiplier, divisor)
+            p = self._format(id, name, algorithm, multiplier, divisor)
+            #self._line("DIMENSION", id, name, algorithm, str(multiplier), str(divisor))
+
+        self._line("DIMENSION", *p)
 
     def begin(self, type_id, microseconds=0):
         """
@@ -224,7 +261,7 @@ class BaseService(threading.Thread):
             self.error("malformed begin statement: microseconds are not a number:", microseconds)
             microseconds = ""
 
-        self._line("BEGIN", type_id, microseconds)
+        self._line("BEGIN", type_id, str(microseconds))
         return True
 
     def set(self, id, value):
@@ -242,7 +279,7 @@ class BaseService(threading.Thread):
         except TypeError:
             self.error("cannot set non-numeric value:", value)
             return False
-        self._line("SET", id, "=", value)
+        self._line("SET", id, "=", str(value))
         return True
 
     def end(self):
@@ -432,11 +469,12 @@ class UrlService(SimpleService):
             return False
 
 
-class NetSocketService(SimpleService):
+class SocketService(SimpleService):
     def __init__(self, configuration=None, name=None):
         self.host = "localhost"
         self.port = None
         self.sock = None
+        self.unix_socket = None
         self.request = ""
         SimpleService.__init__(self, configuration=configuration, name=name)
 
@@ -447,10 +485,16 @@ class NetSocketService(SimpleService):
         """
         if self.sock is None:
             try:
-                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                sock.settimeout(self.update_every)
-                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-                sock.connect((self.host, self.port))
+                if self.unix_socket is None:
+                    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+                    #sock.settimeout(self.update_every)
+                    sock.connect((self.host, self.port))
+                else:
+                    sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+                    #sock.settimeout(self.update_every)
+                    sock.connect(self.unix_socket)
+
             except Exception as e:
                 self.error(e)
                 self.sock = None
@@ -468,11 +512,15 @@ class NetSocketService(SimpleService):
                 self.sock = None
                 return None
 
-        data = sock.recv(1024)
+        data = sock.recv(2)
         try:
             while True:
-                buf = sock.recv(1024)
-                if not buf:
+                try:
+                    buf = sock.recv(1024, 0x40)  # get 1024 bytes in NON-BLOCKING mode
+                except socket.error:
+                    break
+
+                if len(buf) == 0:
                     break
                 else:
                     data += buf
@@ -492,13 +540,17 @@ class NetSocketService(SimpleService):
         else:
             self.name = str(self.name)
         try:
-            self.host = str(self.configuration['host'])
+            self.unix_socket = str(self.configuration['socket'])
         except (KeyError, TypeError):
-            self.error("No host specified. Using: '" + self.host + "'")
-        try:
-            self.port = int(self.configuration['port'])
-        except (KeyError, TypeError):
-            self.error("No port specified. Using: '" + str(self.port) + "'")
+            self.error("No unix socket specified. Trying TCP/IP socket.")
+            try:
+                self.host = str(self.configuration['host'])
+            except (KeyError, TypeError):
+                self.error("No host specified. Using: '" + self.host + "'")
+            try:
+                self.port = int(self.configuration['port'])
+            except (KeyError, TypeError):
+                self.error("No port specified. Using: '" + str(self.port) + "'")
         try:
             self.request = str(self.configuration['request'])
         except (KeyError, TypeError):
@@ -565,6 +617,7 @@ class LogService(SimpleService):
 
 class ExecutableService(SimpleService):
     command_whitelist = ['exim', 'postqueue']
+    bad_substrings = ('&', '|', ';', '>', '<')
 
     def __init__(self, configuration=None, name=None):
         self.command = ""
@@ -582,7 +635,7 @@ class ExecutableService(SimpleService):
             return None
         data = []
         for line in p.stdout.readlines():
-            data.append(line)
+            data.append(str(line.decode()))
 
         return data
 
@@ -600,19 +653,23 @@ class ExecutableService(SimpleService):
         # except (KeyError, TypeError):
         #     self.error("No command specified. Using: '" + self.command + "'")
         self.command = self.command.split(' ')
-        for i in self.command:
-            if i.startswith('-') or i in self.command_whitelist:
-                pass
-            else:
-                self.error("Wrong command. Probably not on whitelist.")
+        if self.command[0] not in self.command_whitelist:
+            self.error("Command is not whitelisted.")
+            return False
+
+        for arg in self.command[1:]:
+            if any(st in arg for st in self.bad_substrings):
+                self.error("Bad command argument:" + " ".join(self.command[1:]))
                 return False
         # test command and search for it in /usr/sbin or /sbin when failed
         base = self.command[0]
         if self._get_raw_data() is None:
             for prefix in ['/sbin/', '/usr/sbin/']:
                 self.command[0] = prefix + base
-                if self._get_raw_data() is not None:
+                if os.path.isfile(self.command[0]):
                     break
+                #if self._get_raw_data() is not None:
+                #    break
 
         if self._get_data() is None or len(self._get_data()) == 0:
             return False
index 3f168895510386dcaea2a2a5cc199576e5c6cfd4..5ff4e79ba92b7ead2d28bd13f79d5324f4760898 100644 (file)
@@ -12,10 +12,8 @@ def log_msg(msg_type, *args):
     Print message on stderr.
     :param msg_type: str
     """
-    msg = PROGRAM + " " + str(msg_type) + ":"
-    for i in args:
-        msg += " "
-        msg += str(i)
+    msg = "%s %s: %s" % (PROGRAM, str(msg_type), " ".join(args))
+
     sys.stderr.write(msg + "\n")
     sys.stderr.flush()
 
diff --git a/python.d/redis.chart.py b/python.d/redis.chart.py
new file mode 100644 (file)
index 0000000..7a0e91b
--- /dev/null
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+# Description: redis netdata python.d module
+# Author: Pawel Krupa (paulfantom)
+
+from base import SocketService
+
+# default module values (can be overridden per job in `config`)
+#update_every = 2
+priority = 60000
+retries = 5
+
+# default job configuration (overridden by python.d.plugin)
+# config = {'local': {
+#             'update_every': update_every,
+#             'retries': retries,
+#             'priority': priority,
+#             'host': 'localhost',
+#             'port': 6379,
+#             'unix_socket': None
+#          }}
+
+ORDER = ['operations', 'hit_rate', 'memory', 'keys', 'clients', 'slaves']
+
+CHARTS = {
+    'operations': {
+        'options': [None, 'Operations', 'operations/s', 'Statistics', 'redis.statistics', 'line'],
+        'lines': [
+            ['instantaneous_ops_per_sec', 'operations', 'absolute']
+        ]},
+    'hit_rate': {
+        'options': [None, 'Hit rate', 'percent', 'Statistics', 'redis.statistics', 'line'],
+        'lines': [
+            ['hit_rate', 'rate', 'absolute']
+        ]},
+    'memory': {
+        'options': [None, 'Memory utilization', 'kilobytes', 'Memory', 'redis.memory', 'line'],
+        'lines': [
+            ['used_memory', 'total', 'absolute', 1, 1024],
+            ['used_memory_lua', 'lua', 'absolute', 1, 1024]
+        ]},
+    'keys': {
+        'options': [None, 'Database keys', 'keys', 'Keys', 'redis.keys', 'line'],
+        'lines': [
+            # lines are created dynamically in `check()` method
+        ]},
+    'clients': {
+        'options': [None, 'Clients', 'clients', 'Clients', 'redis.clients', 'line'],
+        'lines': [
+            ['connected_clients', 'connected', 'absolute'],
+            ['blocked_clients', 'blocked', 'absolute']
+        ]},
+    'slaves': {
+        'options': [None, 'Slaves', 'slaves', 'Replication', 'redis.replication', 'line'],
+        'lines': [
+            ['connected_slaves', 'connected', 'absolute']
+        ]}
+}
+
+
+class Service(SocketService):
+    def __init__(self, configuration=None, name=None):
+        SocketService.__init__(self, configuration=configuration, name=name)
+        self.request = "INFO\r\n"
+        self.host = "localhost"
+        self.port = 6379
+        self.unix_socket = None
+        self.order = ORDER
+        self.definitions = CHARTS
+
+    def _get_data(self):
+        """
+        Get data from socket
+        :return: dict
+        """
+        try:
+            raw = self._get_raw_data().split("\n")
+        except AttributeError:
+            return None
+        data = {}
+        for line in raw:
+            if line.startswith(('instantaneous', 'keyspace', 'used_memory', 'connected', 'blocked')):
+                try:
+                    t = line.split(':')
+                    data[t[0]] = int(t[1])
+                except (IndexError, ValueError):
+                    pass
+            elif line.startswith('db'):
+                tmp = line.split(',')[0].replace('keys=', '')
+                record = tmp.split(':')
+                data[record[0]] = int(record[1])
+        try:
+            data['hit_rate'] = int((data['keyspace_hits'] / float(data['keyspace_hits'] + data['keyspace_misses'])) * 100)
+        except:
+            data['hit_rate'] = 0
+
+        return data
+
+    def check(self):
+        """
+        Parse configuration, check if redis is available, and dynamically create chart lines data
+        :return: boolean
+        """
+        self._parse_config()
+        if self.name == "":
+            self.name = "local"
+        self.chart_name += "_" + self.name
+        data = self._get_data()
+        if data is None:
+            self.error("No data received")
+            return False
+
+        for name in data:
+            if name.startswith('db'):
+                self.definitions['keys']['lines'].append([name.decode(), None, 'absolute'])
+
+        return True
index f68ce7e57c9950d1223be0fc628a4a9481cf8b18..9d50198fceaa0272a8a9b0c9056d772ca452fefa 100644 (file)
@@ -2,7 +2,7 @@
 # Description: squid netdata python.d module
 # Author: Pawel Krupa (paulfantom)
 
-from base import NetSocketService
+from base import SocketService
 
 # default module values (can be overridden per job in `config`)
 # update_every = 2
@@ -14,7 +14,7 @@ ORDER = ['clients_net', 'clients_requests', 'servers_net', 'servers_requests']
 
 CHARTS = {
     'clients_net': {
-        'options': [None, "Squid Client Bandwidth", "kilobits/s", "clients", "squid.clients.net" "area"],
+        'options': [None, "Squid Client Bandwidth", "kilobits/s", "clients", "squid.clients.net", "area"],
         'lines': [
             ["client_http_kbytes_in", "in", "incremental", 8, 1],
             ["client_http_kbytes_out", "out", "incremental", -8, 1],
@@ -23,12 +23,12 @@ CHARTS = {
     'clients_requests': {
         'options': [None, "Squid Client Requests", "requests/s", "clients", "squid.clients.requests", 'line'],
         'lines': [
-            ["client_http_requests", "requests"],
-            ["client_http_hits", "hits"],
+            ["client_http_requests", "requests", "incremental"],
+            ["client_http_hits", "hits", "incremental"],
             ["client_http_errors", "errors", "incremental", -1, 1]
         ]},
     'servers_net': {
-        'options': [None, "Squid Server Bandwidth", "kilobits/s", "servers", "squid.servers.net" "area"],
+        'options': [None, "Squid Server Bandwidth", "kilobits/s", "servers", "squid.servers.net", "area"],
         'lines': [
             ["server_all_kbytes_in", "in", "incremental", 8, 1],
             ["server_all_kbytes_out", "out", "incremental", -8, 1]
@@ -42,9 +42,9 @@ CHARTS = {
 }
 
 
-class Service(NetSocketService):
+class Service(SocketService):
     def __init__(self, configuration=None, name=None):
-        NetSocketService.__init__(self, configuration=configuration, name=name)
+        SocketService.__init__(self, configuration=configuration, name=name)
         self.request = ""
         self.host = "localhost"
         self.port = 3128
@@ -56,19 +56,22 @@ class Service(NetSocketService):
         Get data via http request
         :return: dict
         """
+        data = {}
         try:
-            raw = self._get_raw_data().split('\n')
-            if "200 OK" not in raw[0]:
+            raw = self._get_raw_data().split('\r\n')[-1]
+            if raw.startswith('<'):
                 return None
-            data = {}
-            for row in raw:
+            for row in raw.split('\n'):
                 if row.startswith(("client", "server.all")):
                     tmp = row.split("=")
                     data[tmp[0].replace('.', '_').strip(' ')] = int(tmp[1])
+        except (ValueError, AttributeError, TypeError):
+            return None
 
-            return data
-        except (ValueError, AttributeError):
+        if len(data) == 0:
             return None
+        else:
+            return data
 
     def check(self):
         """
@@ -83,30 +86,8 @@ class Service(NetSocketService):
         if not req.endswith(" HTTP/1.0\r\n\r\n"):
             req += " HTTP/1.0\r\n\r\n"
         self.request = req.encode()
-        #
-        # # autodetect squid
-        # if type(self.port) is tuple:
-        #     ports = self.port
-        #     for port in ports:
-        #         self.port = port
-        #         urls = ["cache_object://" + self.host + ":" + str(port) + "/counters",
-        #                 "/squid-internal-mgr/counters"]
-        #         for url in urls:
-        #             tmp = "GET " + url + " HTTP/1.0\r\n\r\n"
-        #             self.request = tmp.encode()
-        #             if self._get_data() is not None:
-        #                 return True
-        # else:
-        if True:
-            if self._get_data() is not None:
-                return True
-            else:
-                return False
-            
-                
-                
-                
-            
-                
-            
-
+        if self._get_data() is not None:
+            return True
+        else:
+            self.error("No data returned")
+            return False
index 69770e145e90c50cd76ca7704387146f0be0fbc3..a8f26856e764e9a2e7073d284bb4c4e5ce044ebc 100644 (file)
@@ -1362,16 +1362,21 @@ var menuData = {
                info: undefined
        },
 
+       'redis': {
+               title: 'Redis',
+               info: undefined
+       },
+
        'phpfpm': {
                title: 'PHP-FPM',
                info: undefined,
        },
 
-/*     'nginx': {
+       'nginx': {
                title: 'nginx',
                info: undefined,
        },
-
+/*
        'apache': {
                title: 'Apache',
                info: undefined,
@@ -1730,14 +1735,14 @@ var chartData = {
                height: 0.5
        },
 
-       'nginx.connections': {
+       'nginx_local.connections': {
                colors: NETDATA.colors[4],
                mainheads: [
                        gaugeChart('Connections', '12%', '', NETDATA.colors[4])
                ]
        },
 
-       'nginx.requests': {
+       'nginx_local.requests': {
                colors: NETDATA.colors[0],
                mainheads: [
                        gaugeChart('Requests', '12%', '', NETDATA.colors[0])
@@ -1816,9 +1821,10 @@ function enrichChartData(chart) {
                        break;
 
                case 'mysql':
+               case 'redis':
                case 'phpfpm':
-/*             case 'nginx':
-               case 'apache':*/
+               case 'nginx':
+/*             case 'apache':*/
                case 'named':
                case 'cgroup':
                        chart.menu = chart.type;