]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #600 from paulfantom/master
authorCosta Tsaousis <costa@tsaousis.gr>
Wed, 22 Jun 2016 21:31:58 +0000 (00:31 +0300)
committerGitHub <noreply@github.com>
Wed, 22 Jun 2016 21:31:58 +0000 (00:31 +0300)
Python and Shell fixes + apache and nginx python modules.

charts.d/apache.chart.sh
conf.d/Makefile.am
conf.d/python.d.conf
plugins.d/python.d.plugin
python.d/Makefile.am
python.d/apache.chart.py [new file with mode: 0644]
python.d/nginx.chart.py [new file with mode: 0644]
python.d/phpfpm.chart.py
python.d/python_modules/base.py
web/index.html

index a3e064094c36a357582ceb8c6a3004966fc89bfc..681651a0df303e5c46325b61409592379a78c633 100755 (executable)
@@ -238,7 +238,7 @@ SET connections = $((apache_connstotal))
 END
 BEGIN apache.conns_async $1
 SET keepalive = $((apache_connsasynckeepalive))
-SET closing = $((apache_connsasyncwriting))
+SET closing = $((apache_connsasyncclosing))
 SET writing = $((apache_connsasyncwriting))
 END
 VALUESEOF2
index f60faaa570a65af29ec793592c5a10714f6f4319..5dbc29e19c72fe1bf66013902a4fe41899f42a88 100644 (file)
@@ -21,6 +21,7 @@ pythonconfigdir=$(configdir)/python.d
 dist_pythonconfig_DATA = \
        python.d/example.conf \
        python.d/mysql.conf \
+       python.d/phpfpm.conf \
        $(NULL)
 
 
index b303cde4a88dc0bd80a879549174a85dfcf91c04..d416cf9c9eef071688cd5d62205952fea6f6a348 100644 (file)
@@ -8,3 +8,5 @@ enabled: no
 example: yes
 mysql: yes
 phpfpm: yes
+apache: yes
+nginx: yes
index 0a0e65ae2e0d1912ecb20a9b68eb6eb4cf48cfde..e9f1d5de839e01c4a4c59bd5a8efec614949bc9f 100755 (executable)
@@ -198,8 +198,8 @@ class PythonCharts(object):
             # scan directory specified in path and load all modules from there
             names = os.listdir(path)
             for mod in names:
-                if mod.strip(MODULE_EXTENSION) in disabled:
-                    error(mod + ": disabled module ", mod.strip(MODULE_EXTENSION))
+                if mod.replace(MODULE_EXTENSION, "") in disabled:
+                    error(mod + ": disabled module ", mod.replace(MODULE_EXTENSION, ""))
                     continue
                 m = self._import_module(path + mod)
                 if m is not None:
@@ -220,6 +220,8 @@ class PythonCharts(object):
             if os.path.isfile(configfile):
                 debug(mod.__name__ + ": loading module configuration: '" + configfile + "'")
                 try:
+                    if not hasattr(mod, 'config'):
+                        mod.config = {}
                     setattr(mod,
                             'config',
                             self._parse_config(mod, read_config(configfile)))
@@ -263,7 +265,7 @@ class PythonCharts(object):
                 try:
                     # get defaults from module source code
                     defaults[key] = getattr(module, key)
-                except (KeyError, ValueError):
+                except (KeyError, ValueError, AttributeError):
                     # if above failed, get defaults from global dict
                     defaults[key] = BASE_CONFIG[key]
 
@@ -475,7 +477,10 @@ class PythonCharts(object):
                     i += 1
             if len(next_runs) == 0:
                 fatal('no python.d modules loaded.')
-            time.sleep(min(next_runs) - time.time())
+            try:
+                time.sleep(min(next_runs) - time.time())
+            except IOError:
+                pass
 
 
 def read_config(path):
@@ -526,7 +531,7 @@ def parse_cmdline(directory, *commands):
                 pass
     if changed_update and DEBUG_FLAG:
         OVERRIDE_UPDATE_EVERY = True
-        debug(PROGRAM, "overriding update interval to", str(int(cmd)))
+        debug(PROGRAM, "overriding update interval to", str(BASE_CONFIG['update_every']))
 
     debug("started from", commands[0], "with options:", *commands[1:])
 
index eef6594bb2d056f27a758647dd9305678f24ac7f..b1de3ecc09981d08457a3b3ab223cd14134b89fa 100644 (file)
@@ -7,6 +7,9 @@ SUFFIXES = .in
 dist_python_SCRIPTS = \
        example.chart.py \
        mysql.chart.py \
+       phpfpm.chart.py \
+       apache.chart.py \
+       nginx.chart.py \
        python-modules-installer.sh \
        $(NULL)
 
diff --git a/python.d/apache.chart.py b/python.d/apache.chart.py
new file mode 100644 (file)
index 0000000..94b0571
--- /dev/null
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+# Description: apache netdata python.d plugin
+# Author: Pawel Krupa (paulfantom)
+
+from base import UrlService
+
+# 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,
+#             'url': 'http://www.apache.org/server-status?auto'
+#          }}
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = ['requests', 'connections', 'conns_async', 'net', 'workers', 'reqpersec', 'bytespersec', 'bytesperreq']
+
+CHARTS = {
+    'bytesperreq': {
+        'options': "'' 'apache Lifetime Avg. Response Size' 'bytes/request' statistics apache.bytesperreq area",
+        'lines': [
+            {"name": "size_req",
+             "options": "'' absolute 1 1"}
+        ]},
+    'workers': {
+        'options': "'' 'apache Workers' 'workers' workers apache.workers stacked",
+        'lines': [
+            {"name": "idle",
+             "options": "'' absolute 1 1"},
+            {"name": "busy",
+             "options": "'' absolute 1 1"}
+        ]},
+    'reqpersec': {
+        'options': "'' 'apache Lifetime Avg. Requests/s' 'requests/s' statistics apache.reqpersec area",
+        'lines': [
+            {"name": "requests_sec",
+             "options": "'' absolute 1 1"}
+        ]},
+    'bytespersec': {
+        'options': "'' 'apache Lifetime Avg. Bandwidth/s' 'kilobytes/s' statistics apache.bytesperreq area",
+        'lines': [
+            {"name": "size_sec",
+             "options": "'' absolute 1 1000"}
+        ]},
+    'requests': {
+        'options': "'' 'apache Requests' 'requests/s' requests apache.requests line",
+        'lines': [
+            {"name": "requests",
+             "options": "'' incremental 1 1"}
+        ]},
+    'net': {
+        'options': "'' 'apache Bandwidth' 'kilobytes/s' bandwidth apache.net area",
+        'lines': [
+            {"name": "sent",
+             "options": "'' incremental 1 1"}
+        ]},
+    'connections': {
+        'options': "'' 'apache Connections' 'connections' connections apache.connections line",
+        'lines': [
+            {"name": "connections",
+             "options": "'' absolute 1 1"}
+        ]},
+    'conns_async': {
+        'options': "'' 'apache Async Connections' 'connections' connections apache.conns_async stacked",
+        'lines': [
+            {"name": "keepalive",
+             "options": "'' absolute 1 1"},
+            {"name": "closing",
+             "options": "'' absolute 1 1"},
+            {"name": "writing",
+             "options": "'' absolute 1 1"}
+        ]}
+}
+
+
+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/server-status?auto"
+        self.order = ORDER
+        self.charts = CHARTS
+        self.assignment = {"BytesPerReq": 'size_req',
+                           "IdleWorkers": 'idle',
+                           "BusyWorkers": 'busy',
+                           "ReqPerSec": 'requests_sec',
+                           "BytesPerSec": 'size_sec',
+                           "Total Accesses": 'requests',
+                           "Total kBytes": 'sent',
+                           "ConnsTotal": 'connections',
+                           "ConnsAsyncKeepAlive": 'keepalive',
+                           "ConnsAsyncClosing": 'closing',
+                           "ConnsAsyncWriting": 'writing'}
+
+    def _formatted_data(self):
+        """
+        Format data received from http request
+        :return: dict
+        """
+        try:
+            raw = self._get_data().split("\n")
+        except AttributeError:
+            return None
+        data = {}
+        for row in raw:
+            tmp = row.split(":")
+            if str(tmp[0]) in self.assignment:
+                try:
+                    data[self.assignment[tmp[0]]] = int(float(tmp[1]))
+                except (IndexError, ValueError) as a:
+                    print(a)
+                    pass
+        if len(data) == 0:
+            return None
+        return data
diff --git a/python.d/nginx.chart.py b/python.d/nginx.chart.py
new file mode 100644 (file)
index 0000000..89752f5
--- /dev/null
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+# Description: nginx netdata python.d plugin
+# Author: Pawel Krupa (paulfantom)
+
+from base import UrlService
+
+# 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,
+#             'url': 'http://localhost/stub_status'
+#          }}
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = ['connections', 'requests', 'connection_status', 'connect_rate']
+
+CHARTS = {
+    'connections': {
+        'options': "'' 'nginx Active Connections' 'connections' nginx nginx.connections line",
+        'lines': [
+            {"name": "active",
+             "options": "'' absolute 1 1"}
+        ]},
+    'requests': {
+        'options': "'' 'nginx Requests' 'requests/s' nginx nginx.requests line",
+        'lines': [
+            {"name": "requests",
+             "options": "'' incremental 1 1"}
+        ]},
+    'connection_status': {
+        'options': "'' 'nginx Active Connections by Status' 'connections' nginx nginx.connection.status line",
+        'lines': [
+            {"name": "reading",
+             "options": "'' absolute 1 1"},
+            {"name": "writing",
+             "options": "'' absolute 1 1"},
+            {"name": "waiting",
+             "options": "idle absolute 1 1"}
+        ]},
+    'connect_rate': {
+        'options': "'' 'nginx Connections Rate' 'connections/s' nginx nginx.performance line",
+        'lines': [
+            {"name": "accepts",
+             "options": "accepted incremental 1 1"},
+            {"name": "handled",
+             "options": "'' incremental 1 1"}
+        ]}
+}
+
+
+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/stub_status"
+        self.order = ORDER
+        self.charts = CHARTS
+
+    def _formatted_data(self):
+        """
+        Format data received from http request
+        :return: dict
+        """
+        try:
+            raw = self._get_data().split(" ")
+            return {'active': int(raw[2]),
+                    'requests': int(raw[7]),
+                    'reading': int(raw[11]),
+                    'writing': int(raw[13]),
+                    'waiting': int(raw[15]),
+                    'accepts': int(raw[8]),
+                    'handled': int(raw[9])}
+        except (ValueError, AttributeError):
+            return None
index 31bd2fdbb748ed498139b318ecf3d2ff7391fae7..8fadf2beefa2ce8b5ed8b8abce19bef4b587f3de 100755 (executable)
@@ -6,8 +6,8 @@ from base import UrlService
 
 # default module values (can be overridden per job in `config`)
 # update_every = 2
-priority = 60000
-retries = 5
+priority = 60000
+retries = 5
 
 # default job configuration (overridden by python.d.plugin)
 # config = {'local': {
@@ -50,28 +50,36 @@ CHARTS = {
 
 
 class Service(UrlService):
-    url = "http://localhost/status"
-    order = ORDER
-    charts = CHARTS
-    assignment = {"active processes": 'active',
-                  "max active processes": 'maxActive',
-                  "idle processes": 'idle',
-                  "accepted conn": 'requests',
-                  "max children reached": 'reached',
-                  "slow requests": 'slow'}
+    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.order = ORDER
+        self.charts = CHARTS
+        self.assignment = {"active processes": 'active',
+                           "max active processes": 'maxActive',
+                           "idle processes": 'idle',
+                           "accepted conn": 'requests',
+                           "max children reached": 'reached',
+                           "slow requests": 'slow'}
 
     def _formatted_data(self):
         """
         Format data received from http request
         :return: dict
         """
-        raw = self._get_data().split('\n')
+        try:
+            raw = self._get_data().split('\n')
+        except AttributeError:
+            return None
         data = {}
         for row in raw:
             tmp = row.split(":")
             if str(tmp[0]) in self.assignment:
                 try:
                     data[self.assignment[tmp[0]]] = int(tmp[1])
-                except (IndexError, ValueError) as a:
+                except (IndexError, ValueError):
                     pass
+        if len(data) == 0:
+            return None
         return data
index 1b958dec124ee8f2765f99a819158b3dc02497bd..710ead1bd95036e7450beb2f587b6bff99c6897d 100644 (file)
@@ -97,37 +97,43 @@ class BaseService(object):
 
 
 class UrlService(BaseService):
-    charts = {}
-    # charts definitions in format:
-    # charts = {
-    #    'chart_name_in_netdata': {
-    #        'options': "parameters defining chart (passed to CHART statement)",
-    #        'lines': [
-    #           { 'name': 'dimension_name',
-    #             'options': 'dimension parameters (passed to DIMENSION statement)"
-    #           }
-    #        ]}
-    #    }
-    order = []
-    definitions = {}
-    # definitions are created dynamically in create() method based on 'charts' dictionary. format:
-    # definitions = {
-    #     'chart_name_in_netdata' : [ charts['chart_name_in_netdata']['lines']['name'] ]
-    # }
-    url = ""
+    def __init__(self, configuration=None, name=None):
+        self.charts = {}
+        # charts definitions in format:
+        # charts = {
+        #    'chart_name_in_netdata': {
+        #        'options': "parameters defining chart (passed to CHART statement)",
+        #        'lines': [
+        #           { 'name': 'dimension_name',
+        #             'options': 'dimension parameters (passed to DIMENSION statement)"
+        #           }
+        #        ]}
+        #    }
+        self.order = []
+        self.definitions = {}
+        # definitions are created dynamically in create() method based on 'charts' dictionary. format:
+        # definitions = {
+        #     'chart_name_in_netdata' : [ charts['chart_name_in_netdata']['lines']['name'] ]
+        # }
+        self.url = ""
+        BaseService.__init__(self, configuration=configuration, name=name)
 
     def _get_data(self):
         """
         Get raw data from http request
         :return: str
         """
+        raw = None
         try:
-            f = urlopen(self.url)
+            f = urlopen(self.url, timeout=self.update_every)
             raw = f.read().decode('utf-8')
-            f.close()
         except Exception as e:
             self.error(self.__module__, str(e))
-            return None
+        finally:
+            try:
+                f.close()
+            except:
+                pass
         return raw
 
     def _formatted_data(self):
index e7638317fb40c8544d2973a9b4c2dd4d1c90559e..558127e4211037a2ecd01664c2401f5ecd3f4a61 100644 (file)
@@ -1366,6 +1366,16 @@ var menuData = {
                info: undefined,
        },
 
+/*     'nginx': {
+               title: 'nginx',
+               info: undefined,
+       },
+
+       'apache': {
+               title: 'Apache',
+               info: undefined,
+       },*/
+
        'named': {
                title: 'named',
                info: undefined
@@ -1806,6 +1816,8 @@ function enrichChartData(chart) {
 
                case 'mysql':
                case 'phpfpm':
+/*             case 'nginx':
+               case 'apache':*/
                case 'named':
                case 'cgroup':
                        chart.menu = chart.type;