SimpleService and Charts optimization
lgz committed
Nov 3, 2017 at 00:22 UTC
1368fdfc0097defc704b3953c47d17ec48e3ac16
2 files changed
+85
-92
python.d/python_modules/bases/FrameworkServices/SimpleService.py
+14
-40
@@ -149,10 +149,6 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
149
del self.order
150
del self.definitions
151
152
- # push charts to netdata
153
- for chart in self.charts:
154
- safe_print(chart.create())
155
-
152
# True if job has at least 1 chart else False
153
return bool(self.charts)
154
@@ -209,55 +205,33 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
205
self.debug('get_data() returned incorrect type data')
206
return False
207
212
- charts_updated = False
213
-
214
- for chart in self.charts.penalty_exceeded(penalty_max=CHART_OBSOLETE_PENALTY):
215
- safe_print(chart.obsolete())
216
- chart.suppress()
217
- self.error("chart '{0}' was removed due to non updating".format(chart.name))
208
+ updated = False
209
210
for chart in self.charts:
220
- if not chart.alive:
221
- continue
222
- dimension_updated, variables_updated = str(), str()
211
224
- for dimension in chart:
225
- try:
226
- value = int(data[dimension.id])
227
- except (KeyError, TypeError):
228
- continue
229
- else:
230
- dimension_updated += dimension.set(value)
212
+ if chart.flags.obsolete:
213
+ continue
214
+ elif chart.penalty > CHART_OBSOLETE_PENALTY:
215
+ chart.push_obsolete()
216
+ self.error("chart '{0}' was removed due to non updating".format(chart.name))
217
+ continue
218
232
- for var in chart.variables:
233
- try:
234
- value = int(data[var.id])
235
- except (KeyError, TypeError):
236
- continue
237
- else:
238
- variables_updated += var.set(value)
239
-
240
- if dimension_updated:
241
- charts_updated = True
242
- safe_print(''.join([chart.begin(since_last=interval),
243
- dimension_updated,
244
- variables_updated,
245
- 'END\n']))
246
- else:
247
- chart.penalty += 1
219
+ since_last = 0 if chart.flags.new else interval
220
+ ok = chart.update(data, since_last)
221
+ if ok:
222
+ updated = True
223
249
- if not charts_updated:
224
+ if not updated:
225
self.debug('none of the charts have been updated')
226
252
- return charts_updated
227
+ return updated
228
229
def manage_retries(self):
230
self._runtime_counters.RETRIES += 1
231
if self._runtime_counters.RETRIES % 5 == 0:
232
self._runtime_counters.PENALTY = int(self._runtime_counters.RETRIES * self.update_every / 2)
233
if self._runtime_counters.RETRIES >= self._runtime_counters.RETRIES_MAX:
259
- self.error('stopped after {retries_max} data '
260
- 'collection failures in a row'.format(retries_max=self._runtime_counters.RETRIES_MAX))
234
+ self.error('stopped after {0} data collection failures in a row'.format(self._runtime_counters.RETRIES_MAX))
235
return False
236
return True
237
python.d/python_modules/bases/charts.py
+71
-52
@@ -109,13 +109,6 @@ class Charts:
109
def __nonzero__(self):
110
return self.__bool__()
111
112
- def penalty_exceeded(self, penalty_max):
113
- """
114
- :param penalty_max: <int>
115
- :return:
116
- """
117
- return (chart for chart in self if chart.penalty > penalty_max and chart.alive)
118
-
112
def add_chart(self, params):
113
"""
114
Create Chart instance and add it to the dict
@@ -125,16 +118,16 @@ class Charts:
118
:return:
119
"""
120
params = [self.job_name()] + params
128
- chart_id = params[1]
129
- if chart_id in self.charts:
130
- raise DuplicateItemError("'{chart}' already in charts".format(chart=chart_id))
131
- else:
132
- new_chart = Chart(params)
133
- new_chart.params['update_every'] = self.get_update_every()
134
- new_chart.params['priority'] = self.priority
135
- self.priority += 1
136
- self.charts[new_chart.id] = new_chart
137
- return new_chart
121
+ new_chart = Chart(params)
122
+ new_chart.params['update_every'] = self.get_update_every()
123
+ new_chart.params['priority'] = self.priority
124
+ self.priority += 1
125
+ self.charts[new_chart.id] = new_chart
126
+
127
+ return new_chart
128
+
129
+ def active_charts(self):
130
+ return [chart.id for chart in self if not chart.flags.obsolete]
131
132
133
class Chart:
@@ -156,7 +149,7 @@ class Chart:
149
150
self.dimensions = list()
151
self.variables = set()
159
- self.alive = True
152
+ self.flags = ChartFlags()
153
self.penalty = 0
154
155
def __getattr__(self, item):
@@ -178,13 +171,6 @@ class Chart:
171
def __contains__(self, item):
172
return item in [dimension.id for dimension in self.dimensions]
173
181
- def suppress(self):
182
- self.alive = False
183
-
184
- def unsuppress(self):
185
- self.penalty = 0
186
- self.alive = True
187
-
174
def add_variable(self, variable):
175
"""
176
:param variable: <list>
@@ -202,43 +188,69 @@ class Chart:
188
if dim.id in self:
189
raise DuplicateItemError("'{dimension}' already in '{chart}' dimensions".format(dimension=dim.id,
190
chart=self.name))
191
+ self.refresh()
192
self.dimensions.append(dim)
193
return dim
194
208
- def add_dimension_and_push_chart(self, dimension):
209
- """
210
- :param dimension: <list>
211
- :return:
212
- """
213
- dim = self.add_dimension(dimension)
214
- self.unsuppress()
215
- safe_print(self.create(dim))
216
-
217
- def create(self, dimension=None):
195
+ def create(self):
196
"""
219
- :param dimension: Dimension
197
:return:
198
"""
199
chart = CHART_CREATE.format(**self.params)
223
- if not dimension:
224
- dimensions = ''.join([dimension.create() for dimension in self.dimensions])
225
- variables = ''.join([var.set(var.value) for var in self.variables if var])
226
- return chart + dimensions + variables
200
+ dimensions = ''.join([dimension.create() for dimension in self.dimensions])
201
+ variables = ''.join([var.set(var.value) for var in self.variables if var])
202
+
203
+ return chart + dimensions + variables
204
+
205
+ def push_obsolete(self):
206
+ self.flags.obsolete = True
207
+ safe_print(CHART_OBSOLETE.format(**self.params))
208
+
209
+ def update(self, data, since_last):
210
+ updated_dimensions, updated_variables = str(), str()
211
+
212
+ for dimension in self.dimensions:
213
+ try:
214
+ value = int(data[dimension.id])
215
+ except (KeyError, TypeError):
216
+ continue
217
+ else:
218
+ updated_dimensions += dimension.set(value)
219
+
220
+ for var in self.variables:
221
+ try:
222
+ value = int(data[var.id])
223
+ except (KeyError, TypeError):
224
+ continue
225
+ else:
226
+ updated_variables += var.set(value)
227
+
228
+ if updated_dimensions:
229
+ if self.flags.push:
230
+ self.push_created()
231
+
232
+ chart_begin = CHART_BEGIN.format(type=self.type, id=self.id, since_last=since_last)
233
+ self.push_updates(chart_begin, updated_dimensions, updated_variables, 'END\n')
234
else:
228
- dimensions = dimension.create()
229
- return chart + dimensions
235
+ self.penalty += 1
236
231
- def begin(self, since_last):
232
- """
233
- :param since_last: <int>: microseconds
234
- :return:
235
- """
236
- return CHART_BEGIN.format(type=self.type,
237
- id=self.id,
238
- since_last=since_last)
237
+ return bool(updated_dimensions)
238
+
239
+ def push_created(self):
240
+ self.penalty = 0
241
+ self.flags.push = False
242
+ self.flags.new = False
243
+ safe_print(self.create())
244
240
- def obsolete(self):
241
- return CHART_OBSOLETE.format(**self.params)
245
+ @staticmethod
246
+ def push_updates(*data):
247
+ safe_print(''.join(data))
248
+
249
+ def refresh(self):
250
+ self.flags.push = True
251
+ if self.flags.obsolete:
252
+ self.flags.new = True
253
+ self.flags.obsolete = False
254
255
256
class Dimension:
@@ -332,3 +344,10 @@ class ChartVariable:
344
def set(self, value):
345
return CHART_VARIABLE_SET.format(id=self.id,
346
value=value)
347
+
348
+
349
+class ChartFlags:
350
+ def __init__(self):
351
+ self.new = True
352
+ self.obsolete = False
353
+ self.push = True