@cryptotaxi247 / netdata-1 / commits / 77563deee

New class UrlService + phpfpm python module + minor changes in python.d.conf

paulfantom committed Jun 22, 2016 at 13:12 UTC 77563deeed3129bbe1fd5a9996633b874bbffeff
4 files changed +217 -8
conf.d/python.d.conf
+3 -2
@@ -5,5 +5,6 @@ enabled: no
5
6 # By default python.d.plugin enables all modules stored in python.d
7 # Modules can be disabled with setting "module_name = no"
8 -example: no
9 -mysql: no
8 +example: yes
9 +mysql: yes
10 +phpfpm: yes
conf.d/python.d/phpfpm.conf new
+4
@@ -0,0 +1,4 @@
1 +update_every: 3
2 +
3 +local:
4 + url: "http://localhost/status"
\ No newline at end of file
python.d/phpfpm.chart.py new
+77
@@ -0,0 +1,77 @@
1 +# -*- coding: utf-8 -*-
2 +# Description: PHP-FPM netdata python.d plugin
3 +# Author: Pawel Krupa (paulfantom)
4 +
5 +from base import UrlService
6 +
7 +# default module values (can be overridden per job in `config`)
8 +update_every = 2
9 +priority = 60000
10 +retries = 5
11 +
12 +# default job configuration (overridden by python.d.plugin)
13 +config = {'local': {
14 + 'update_every': update_every,
15 + 'retries': retries,
16 + 'priority': priority,
17 + 'url': 'http://localhost/status'
18 +}}
19 +
20 +# charts order (can be overridden if you want less charts, or different order)
21 +ORDER = ['connections', 'requests', 'performance']
22 +
23 +CHARTS = {
24 + 'connections': {
25 + 'options': "'' 'PHP-FPM Active Connections' 'connections' phpfpm phpfpm.connections line",
26 + 'lines': [
27 + {"name": "active",
28 + "options": "'' absolute 1 1"},
29 + {"name": "maxActive",
30 + "options": "'max active' absolute 1 1"},
31 + {"name": "idle",
32 + "options": "'' absolute 1 1"}
33 + ]},
34 + 'requests': {
35 + 'options': "'' 'PHP-FPM Requests' 'requests/s' phpfpm phpfpm.requests line",
36 + 'lines': [
37 + {"name": "requests",
38 + "options": "'' incremental 1 1"}
39 + ]},
40 + 'performance': {
41 +
42 + 'options': "'' 'PHP-FPM Performance' 'status' phpfpm phpfpm.performance line",
43 + 'lines': [
44 + {"name": "reached",
45 + "options": "'max children reached' absolute 1 1"},
46 + {"name": "slow",
47 + "options": "'slow requests' absolute 1 1"}
48 + ]}
49 +}
50 +
51 +
52 +class Service(UrlService):
53 + url = "http://localhost/status"
54 + order = ORDER
55 + charts = CHARTS
56 + assignment = {"active processes": 'active',
57 + "max active processes": 'maxActive',
58 + "idle processes": 'idle',
59 + "accepted conn": 'requests',
60 + "max children reached": 'reached',
61 + "slow requests": 'slow'}
62 +
63 + def _formatted_data(self):
64 + """
65 + Format data received from http request
66 + :return: dict
67 + """
68 + raw = self._get_data().split('\n')
69 + data = {}
70 + for row in raw:
71 + tmp = row.split(":")
72 + if str(tmp[0]) in self.assignment:
73 + try:
74 + data[self.assignment[tmp[0]]] = int(tmp[1])
75 + except (IndexError, ValueError) as a:
76 + pass
77 + return data
python.d/python_modules/base.py
+133 -6
@@ -1,9 +1,13 @@
1 # -*- coding: utf-8 -*-
2 -# Description: base for netdata python.d plugins
2 +# Description: prototypes for netdata python.d modules
3 # Author: Pawel Krupa (paulfantom)
4
5 from time import time
6 import sys
7 +try:
8 + from urllib.request import urlopen
9 +except ImportError:
10 + from urllib2 import urlopen
11
12
13 class BaseService(object):
@@ -62,7 +66,7 @@ class BaseService(object):
66 @staticmethod
67 def error(msg, exception=""):
68 if exception != "":
65 - exception = " " + str(exception).replace("\n"," ")
69 + exception = " " + str(exception).replace("\n", " ")
70 sys.stderr.write(str(msg)+exception+"\n")
71 sys.stderr.flush()
72
@@ -71,7 +75,7 @@ class BaseService(object):
75 check() prototype
76 :return: boolean
77 """
74 - self.error("Service " + str(self.__name__) + "doesn't implement check() function")
78 + self.error("Service " + str(self.__module__) + "doesn't implement check() function")
79 return False
80
81 def create(self):
@@ -79,13 +83,136 @@ class BaseService(object):
83 create() prototype
84 :return: boolean
85 """
82 - self.error("Service " + str(self.__name__) + "doesn't implement create() function?")
86 + self.error("Service " + str(self.__module__) + "doesn't implement create() function?")
87 return False
88
85 - def update(self):
89 + def update(self, interval):
90 """
91 update() prototype
92 + :param interval: int
93 :return: boolean
94 """
90 - self.error("Service " + str(self.__name__) + "doesn't implement update() function")
95 + self.error("Service " + str(self.__module__) + "doesn't implement update() function")
96 return False
97 +
98 +
99 +class UrlService(BaseService):
100 + charts = {}
101 + # charts definitions in format:
102 + # charts = {
103 + # 'chart_name_in_netdata': (
104 + # "parameters defining chart (passed to CHART statement)",
105 + # [ # dimensions (lines) definitions
106 + # ("dimension_name", "dimension parameters (passed to DIMENSION statement)")
107 + # ])
108 + # }
109 + order = []
110 + definitions = {}
111 + # definitions are created dynamically in create() method based on 'charts' dictionary. format:
112 + # definitions = {
113 + # 'chart_name_in_netdata' : (charts['chart_name_in_netdata'][1], charts['chart_name_in_netdata'][0])
114 + # }
115 + url = ""
116 +
117 + def _get_data(self):
118 + """
119 + Get raw data from http request
120 + :return: str
121 + """
122 + try:
123 + f = urlopen(self.url)
124 + raw = f.read().decode('utf-8')
125 + f.close()
126 + except Exception as e:
127 + self.error(self.__module__, str(e))
128 + return None
129 + return raw
130 +
131 + def _formatted_data(self):
132 + """
133 + Format data received from http request
134 + :return: dict
135 + """
136 + return {}
137 +
138 + def check(self):
139 + """
140 + Format configuration data and try to connect to server
141 + :return: boolean
142 + """
143 + if self.name is None:
144 + self.name = 'local'
145 + else:
146 + self.name = str(self.name)
147 + try:
148 + self.url = str(self.configuration['url'])
149 + except (KeyError, TypeError):
150 + pass
151 +
152 + if self._formatted_data() is not None:
153 + return True
154 + else:
155 + return False
156 +
157 + def create(self):
158 + """
159 + Create charts
160 + :return: boolean
161 + """
162 + for name in self.order:
163 + if name not in self.charts:
164 + continue
165 + self.definitions[name] = []
166 + for line in self.charts[name]['lines']:
167 + self.definitions[name].append(line['name'])
168 +
169 + idx = 0
170 + data = self._formatted_data()
171 + if data is None:
172 + return False
173 + for name in self.order:
174 + header = "CHART " + \
175 + self.__module__ + "_" + \
176 + self.name + "." + \
177 + name + " " + \
178 + self.charts[name]['options'] + " " + \
179 + str(self.priority + idx) + " " + \
180 + str(self.update_every)
181 + content = ""
182 + # check if server has this datapoint
183 + for line in self.charts[name]['lines']:
184 + if line['name'] in data:
185 + content += "DIMENSION " + line['name'] + " " + line['options'] + "\n"
186 +
187 + if len(content) > 0:
188 + print(header)
189 + print(content)
190 + idx += 1
191 +
192 + if idx == 0:
193 + return False
194 + return True
195 +
196 + def update(self, interval):
197 + """
198 + Update charts
199 + :param interval: int
200 + :return: boolean
201 + """
202 + data = self._formatted_data()
203 + if data is None:
204 + return False
205 +
206 + for chart, dimensions in self.definitions.items():
207 + header = "BEGIN " + self.__module__ + "_" + str(self.name) + "." + chart + " " + str(interval)
208 + c = ""
209 + for dim in dimensions:
210 + try:
211 + c += "\nSET " + dim + " = " + str(data[dim])
212 + except KeyError:
213 + pass
214 + if len(c) != 0:
215 + print(header + c)
216 + print("END")
217 +
218 + return True