@cryptotaxi247 / netdata-1 / commits / 3ff50459a

more debug output, minor fixes

lgz committed Oct 17, 2017 at 16:14 UTC 3ff50459a93f4ebe0f6f454d8ccf5e9b673b8b62
3 files changed +151 -135
plugins.d/python.d.plugin
+91 -81
@@ -1,4 +1,3 @@
1 -
1 #!/usr/bin/env bash
2 '''':; exec "$(command -v python || command -v python3 || command -v python2 ||
3 echo "ERROR python IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" # '''
@@ -39,7 +38,7 @@ from bases.loggers import PythonDLogger
38 from bases.collection import setdefault_values, run_and_exit
39
40 BASE_CONFIG = {'update_every': os.getenv('NETDATA_UPDATE_EVERY', 1),
42 - 'retries': 10,
41 + 'retries': 20,
42 'priority': 60000,
43 'autodetection_retry': 0,
44 'name': str()}
@@ -48,11 +47,6 @@ BASE_CONFIG = {'update_every': os.getenv('NETDATA_UPDATE_EVERY', 1),
47 MODULE_EXTENSION = '.chart.py'
48 OBSOLETE_MODULES = ['apache_cache', 'gunicorn_log', 'nginx_log']
49
51 -JOB_INITIALIZE_MSG = 'Job initialization {status}. Module: "{module_name}", job: "{job_name}"{error}.'
52 -JOB_CREATE_CHARTS_MSG = 'CREATE {status}. Number of charts: {number_of_charts}.'
53 -MODULE_LOAD_MSG = 'Module load {status}. Module: "{module_name}", initialized jobs: {jobs_number}.'
54 -UNHANDLED_EXCEPTION = 'Unhandled exception in {method_name}(). Error: {error}.'
55 -
50
51 def module_ok(m):
52 return m.endswith(MODULE_EXTENSION) and m[:-len(MODULE_EXTENSION)] not in OBSOLETE_MODULES
@@ -73,18 +67,17 @@ def multi_job_check(config):
67
68
69 class Job(object):
76 - def __init__(self, initialized_job, module_name, internal_name):
70 + def __init__(self, initialized_job, job_id):
71 """
78 - :param initialized_job: <Class Service>
79 - :param module_name: <str>
80 - :param internal_name: <str>
72 + :param initialized_job: instance of <Class Service>
73 + :param job_id: <str>
74 """
75 self.job = initialized_job
83 - self.internal_name = internal_name # key in Modules.jobs
84 - self.module_name = module_name # needed in Plugin.delete_job
76 + self.id = job_id # key in Modules.jobs()
77 + self.module_name = self.job.__module__ # used in Plugin.delete_job()
78 self.recheck_every = self.job.configuration.pop('autodetection_retry')
86 - self.checked = False # needed in Plugin.check_job
87 - self.created = False # needed in Plugin.create_job_charts
79 + self.checked = False # used in Plugin.check_job()
80 + self.created = False # used in Plugin.create_job_charts()
81 if OVERRIDE_UPDATE_EVERY:
82 self.job.update_every = int(OVERRIDE_UPDATE_EVERY)
83
@@ -112,13 +105,14 @@ class Module(object):
105 """
106 self.service = service
107 self.name = service.__name__
115 - self.config = self.build_jobs_configurations(config)
108 + self.config = self.jobs_configurations_builder(config)
109 self.jobs = OrderedDict()
110 + self.counter = 1
111
112 self.initialize_jobs()
113
114 def __repr__(self):
121 - return '<Class Module "{name}">'.format(name=self.name)
115 + return "<Class Module '{name}'>".format(name=self.name)
116
117 def __iter__(self):
118 return iter(OrderedDict(self.jobs).values())
@@ -133,58 +127,64 @@ class Module(object):
127 return len(self.jobs)
128
129 def __bool__(self):
136 - return bool(len(self.jobs))
130 + return bool(self.jobs)
131
132 def __nonzero__(self):
133 return self.__bool__()
134
141 - def build_jobs_configurations(self, config):
135 + @staticmethod
136 + def jobs_configurations_builder(config):
137 """
138 :param config: <dict>
139 :return:
140 """
141 + counter = 0
142 + job_base_config = dict()
143 +
144 + for attr in BASE_CONFIG:
145 + job_base_config[attr] = config.pop(attr, BASE_CONFIG[attr])
146 +
147 if not config:
147 - return {self.name: dict(BASE_CONFIG)}
148 - if not multi_job_check(config):
149 - return {self.name: setdefault_values(config, BASE_CONFIG)}
150 - else:
151 - jobs, jobs_base_config = OrderedDict(), dict()
152 - for attr in BASE_CONFIG:
153 - jobs_base_config[attr] = config.pop(attr, BASE_CONFIG[attr])
154 - for job_name in config:
155 - if not isinstance(config[job_name], dict):
156 - continue
157 -
158 - defaulted = setdefault_values(config[job_name], base_dict=jobs_base_config)
159 - config[job_name]['name'] = sub(r'\s+', '_', config[job_name]['name'])
160 - job_name = sub(r'\s+', '_', job_name)
161 - job_internal_name = '_'.join([self.name, job_name])
162 - jobs[job_internal_name] = defaulted
163 - return jobs
148 + config = {str(): dict()}
149 + elif not multi_job_check(config):
150 + config = {str(): config}
151 +
152 + for job_name in config:
153 + if not isinstance(config[job_name], dict):
154 + continue
155 +
156 + job_config = setdefault_values(config[job_name], base_dict=job_base_config)
157 + job_name = sub(r'\s+', '_', job_name)
158 + config[job_name]['name'] = sub(r'\s+', '_', config[job_name]['name'])
159 + counter += 1
160 + job_id = 'job' + str(counter).zfill(3)
161 +
162 + yield job_id, job_name, job_config
163
164 def initialize_jobs(self):
166 - for job_internal_name in self.config:
167 - job_name = job_internal_name[len(self.name) + 1:]
168 - job_override_name = self.config[job_internal_name].pop('name')
169 - self.config[job_internal_name]['module_name'] = self.name
170 - self.config[job_internal_name]['job_name'] = job_name
171 - self.config[job_internal_name]['override_name'] = job_override_name
165 + """
166 + :return:
167 + """
168 + for job_id, job_name, job_config in self.config:
169 + job_config['job_name'] = job_name
170 + job_config['override_name'] = job_config.pop('name')
171 +
172 try:
173 - initialized_job = self.service.Service(configuration=self.config[job_internal_name])
173 + initialized_job = self.service.Service(configuration=job_config)
174 except Exception as error:
175 - Logger.error(JOB_INITIALIZE_MSG.format(status='FAILED',
176 - module_name=self.name,
177 - job_name=job_name,
178 - error=', error: {0}'.format(error)))
175 + Logger.error("job initialization: '{module_name} {job_name}' "
176 + "=> [{status}] ({error})".format(status='FAILED',
177 + module_name=self.name,
178 + job_name=job_name,
179 + error=error))
180 continue
181 else:
181 - Logger.debug(JOB_INITIALIZE_MSG.format(status='SUCCESS',
182 - module_name=self.name,
183 - job_name=job_name,
184 - error=''))
185 - self.jobs[job_internal_name] = Job(initialized_job=initialized_job,
186 - module_name=self.name,
187 - internal_name=job_internal_name)
182 + Logger.debug("job initialization: '{module_name} {job_name}' "
183 + "=> [{status}]".format(status='OK',
184 + module_name=self.name,
185 + job_name=job_name or self.name))
186 + self.jobs[job_id] = Job(initialized_job=initialized_job,
187 + job_id=job_id)
188 del self.config
189 del self.service
190
@@ -194,7 +194,7 @@ class Plugin(object):
194 self.loader = ModuleAndConfigLoader()
195 self.modules = OrderedDict()
196 self.sleep_time = 1
197 - self.number_of_runs = 0
197 + self.runs_counter = 0
198 self.config, error = self.loader.load_config_from_file(PLUGIN_CONFIG_DIR + 'python.d.conf')
199 if error:
200 run_and_exit(Logger.error)(error)
@@ -207,7 +207,7 @@ class Plugin(object):
207 run_and_exit(Logger.info)('No modules to run. Exit...')
208
209 def __iter__(self):
210 - return iter(dict(self.modules).values())
210 + return iter(OrderedDict(self.modules).values())
211
212 @property
213 def jobs(self):
@@ -240,19 +240,31 @@ class Plugin(object):
240
241 def load_and_initialize_modules(self):
242 for mod, mod_name, mod_path, conf_path in self.enabled_modules():
243 +
244 + # Load module from file ------------------------------------------------------------
245 loaded_module, error = self.loader.load_module_from_file(mod_name, mod_path)
246 + log = Logger.error if error else Logger.debug
247 + log("module load source: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK',
248 + module_name=mod_name))
249 if error:
245 - Logger.error('Module load failed. Module: {name}, error: {error}.'.format(name=mod,
246 - error=error))
250 + Logger.error("load source error : {0}".format(error))
251 continue
252 +
253 + # Load module config from file ------------------------------------------------------
254 loaded_config, error = self.loader.load_config_from_file(conf_path)
255 + log = Logger.error if error else Logger.debug
256 + log("module load config: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK',
257 + module_name=mod_name))
258 if error:
250 - Logger.error('Config load failed. Module {module}, error: {error}.'.format(module=mod_name,
251 - error=error))
259 + Logger.error('load config error : {0}'.format(error))
260 +
261 + # Service instance initialization ---------------------------------------------------
262 initialized_module = Module(service=loaded_module, config=loaded_config)
253 - Logger.debug(MODULE_LOAD_MSG.format(status='OK' if initialized_module else 'FAILED',
254 - module_name=initialized_module.name,
255 - jobs_number=len(initialized_module)))
263 + Logger.debug("module status: '{module_name}' => [{status}] "
264 + "(jobs: {jobs_number})".format(status='OK' if initialized_module else 'FAILED',
265 + module_name=initialized_module.name,
266 + jobs_number=len(initialized_module)))
267 +
268 if initialized_module:
269 self.modules[initialized_module.name] = initialized_module
270
@@ -263,17 +275,11 @@ class Plugin(object):
275 :return:
276 """
277 try:
266 - check_ok = job.check()
278 + check_ok = bool(job.check())
279 except Exception as error:
268 - job.error(UNHANDLED_EXCEPTION.format(method_name='check',
269 - error=error))
270 - return False
280 + job.error('check() unhandled exception: {error}'.format(error=error))
281 + return None
282 else:
272 - log = job.info if check_ok else job.error
273 - log('CHECK {status}'.format(status='OK' if check_ok else 'FAILED'))
274 - if job.is_autodetect():
275 - if not check_ok:
276 - job.error('Next CHECK in {0} seconds.'.format(job.recheck_every))
283 return check_ok
284
285 @staticmethod
@@ -285,12 +291,9 @@ class Plugin(object):
291 try:
292 create_ok = job.create()
293 except Exception as error:
288 - job.error(UNHANDLED_EXCEPTION.format(method_name='create',
289 - error=error))
294 + job.error('create() unhandled exception: {error}'.format(error=error))
295 return False
296 else:
292 - job.debug(JOB_CREATE_CHARTS_MSG.format(status='OK' if create_ok else 'FAILED',
293 - number_of_charts=len(job.charts)))
297 return create_ok
298
299 def delete_job(self, job):
@@ -298,31 +301,38 @@ class Plugin(object):
301 :param job: <Job>
302 :return:
303 """
301 - del self.modules[job.module_name][job.internal_name]
304 + del self.modules[job.module_name][job.id]
305
306 def run_check(self):
307 checked = list()
308 for job in self.jobs:
309 if job.name in checked:
307 - Logger.info('DROPPED: {job_name}. Already served by another job.'.format(job_name=job.internal_name))
310 + job.info('check() => [DROPPED] (already served by another job)')
311 self.delete_job(job)
312 continue
313 ok = self.check_job(job)
314 if ok:
315 + job.info('check() => [OK]')
316 checked.append(job.name)
317 job.checked = True
318 continue
315 - if not job.is_autodetect():
319 + if not job.is_autodetect() or ok is None:
320 + job.error('check() => [FAILED]')
321 self.delete_job(job)
322 + else:
323 + job.error('check() => [RECHECK] (autodetection_retry: {0})'.format(job.recheck_every))
324
325 def run_create(self):
326 for job in self.jobs:
327 if not job.checked:
328 + # skip autodetection_retry jobs
329 continue
330 ok = self.create_job_charts(job)
331 if ok:
332 + job.debug('create() => [OK] (charts: {0})'.format(len(job.charts)))
333 job.created = True
334 continue
335 + job.error('create() => [FAILED] (charts: {0})'.format(len(job.charts)))
336 self.delete_job(job)
337
338 def start(self):
@@ -348,9 +358,9 @@ class Plugin(object):
358 del self.modules[mod.name]
359
360 def autodetect_retry(self):
351 - self.number_of_runs += self.sleep_time
361 + self.runs_counter += self.sleep_time
362 for job in self.autodetect_jobs:
353 - if self.number_of_runs % job.recheck_every == 0:
363 + if self.runs_counter % job.recheck_every == 0:
364 checked = self.check_job(job)
365 if checked:
366 created = self.create_job_charts(job)
python.d/python_modules/bases/FrameworkServices/SimpleService.py
+43 -42
@@ -16,12 +16,6 @@ from bases.loggers import PythonDLimitedLogger
16
17 CHART_OBSOLETE_PENALTY = 10
18
19 -START_MSG = 'STARTED. Update frequency: {freq}, retries: {retries}.'
20 -UPDATE_MSG = 'UPDATE {status}. Elapsed time: {elapsed}, retries left: {retries}.'
21 -STOP_MSG = 'STOPPED after {retries_max} data collection failures in a row.'
22 -SLEEP_MSG = 'SLEEPING for {sleep_time} to reach frequency of {freq} sec.'
23 -UNHANDLED_EXCEPTION = 'Unhandled exception in {method_name}(). Error: {error}.'
24 -
19 RUNTIME_CHART_UPDATE = 'BEGIN netdata.runtime_{job_name} {since_last}\n' \
20 'SET run_time = {elapsed}\n' \
21 'END\n'
@@ -32,14 +26,14 @@ class RuntimeCounters:
26 """
27 :param configuration: <dict>
28 """
35 - self.FREQ = int(configuration.pop('update_every', 1))
29 + self.FREQ = int(configuration.pop('update_every'))
30 self.START_RUN = 0
31 self.NEXT_RUN = 0
32 self.PREV_UPDATE = 0
33 self.SINCE_UPDATE = 0
34 self.ELAPSED = 0
35 self.RETRIES = 0
42 - self.RETRIES_MAX = configuration.pop('retries', 10)
36 + self.RETRIES_MAX = configuration.pop('retries')
37
38 def is_sleep_time(self):
39 return self.START_RUN < self.NEXT_RUN
@@ -60,15 +54,17 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
54 PythonDLimitedLogger.__init__(self)
55 OldVersionCompatibility.__init__(self)
56 self.configuration = configuration
63 - self.module_name = configuration.pop('module_name')
57 + self.order = list()
58 + self.definitions = dict()
59 +
60 + self.module_name = self.__module__
61 self.job_name = configuration.pop('job_name')
62 self.override_name = configuration.pop('override_name')
63 self.fake_name = None
67 - self.order = list()
68 - self.definitions = dict()
64 +
65 self._runtime_counters = RuntimeCounters(configuration=configuration)
66 self.charts = Charts(job_name=self.actual_name,
71 - priority=configuration.pop('priority', 60000),
67 + priority=configuration.pop('priority'),
68 update_every=self.update_every)
69
70 def __repr__(self):
@@ -101,29 +97,24 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
97 check() prototype
98 :return: boolean
99 """
104 - try:
105 - data = self._get_data()
106 - except Exception as error:
107 - self.debug('CHECK {{error: {error}}}'.format(error=error))
108 - else:
109 - if data and isinstance(data, dict):
110 - return True
111 - self.debug('CHECK returned no data')
112 - return False
100 + self.debug("job doesn't implement check() method. Using default which simply invokes get_data().")
101 + data = self.get_data()
102 + if data and isinstance(data, dict):
103 + return True
104 + self.debug('returned value is wrong: {0}'.format(data))
105 + return False
106
107 @create_runtime_chart
108 def create(self):
109 for chart_name in self.order:
110 chart_config = self.definitions.get(chart_name)
111 if not chart_config:
119 - self.debug('{chart_name} not in definitions'.format(chart_name=chart_name))
112 + self.debug("create() chart '{chart_name}' not in definitions. "
113 + "Skipping it.".format(chart_name=chart_name))
114 continue
115
122 - chart_params = ([chart_name] + chart_config['options'])
123 - ok = self.charts.add_chart(params=chart_params)
124 - if not ok:
125 - self.debug('"{chart}" chart no added'.format(chart=chart_name))
126 - continue
116 + chart_params = [chart_name] + chart_config['options']
117 + self.charts.add_chart(params=chart_params)
118
119 for line in chart_config['lines']:
120 self.charts[chart_name].add_dimension(line)
@@ -131,12 +122,10 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
122 del self.order
123 del self.definitions
124
134 - if self.charts.empty():
135 - return None
136 -
125 for chart in self.charts:
126 safe_print(chart.create())
139 - return True
127 +
128 + return bool(self.charts)
129
130 def run(self):
131 """
@@ -145,7 +134,8 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
134 :return: None
135 """
136 job = self._runtime_counters
148 - self.debug(START_MSG.format(freq=job.FREQ, retries=job.RETRIES_MAX - job.RETRIES))
137 + self.debug('started, update frequency: {freq}, '
138 + 'retries: {retries}'.format(freq=job.FREQ, retries=job.RETRIES_MAX - job.RETRIES))
139
140 while True:
141 job.START_RUN = time()
@@ -160,8 +150,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
150 try:
151 updated = self.update(interval=job.SINCE_UPDATE)
152 except Exception as error:
163 - self.debug(UNHANDLED_EXCEPTION.format(method_name='update',
164 - error=error))
153 + self.debug('update() unhandled exception: {error}'.format(error=error))
154 updated = False
155
156 if not updated:
@@ -175,9 +164,10 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
164 safe_print(RUNTIME_CHART_UPDATE.format(job_name=self.name,
165 since_last=job.SINCE_UPDATE,
166 elapsed=job.ELAPSED))
178 - self.debug(UPDATE_MSG.format(status='OK' if updated else 'FAILED',
179 - elapsed=job.ELAPSED if updated else '-',
180 - retries=job.RETRIES_MAX - job.RETRIES))
167 + self.debug('update => [{status}] (elapsed time: {elapsed}, '
168 + 'retries left: {retries})'.format(status='OK' if updated else 'FAILED',
169 + elapsed=job.ELAPSED if updated else '-',
170 + retries=job.RETRIES_MAX - job.RETRIES))
171
172 def update(self, interval):
173 """
@@ -186,16 +176,22 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
176 """
177 data = self.get_data()
178 if not data:
189 - return None
179 + self.debug('get_data() returns no data')
180 + return False
181 + elif not isinstance(data, dict):
182 + self.debug('get_data() returns incorrect type data')
183 + return False
184 +
185 charts_updated = False
186
187 for chart in self.charts.penalty_exceeded(penalty_max=CHART_OBSOLETE_PENALTY):
188 safe_print(chart.obsolete())
189 del self.charts[chart.params['id']]
190 + self.error('chart "{0}" was removed due to non updating'.format(chart.name))
191
192 for chart in self.charts:
193 dimension_updated = str()
198 - for dimension in chart.dimensions:
194 + for dimension in chart:
195 try:
196 value = int(data[dimension.params['id']])
197 except (KeyError, TypeError):
@@ -208,12 +204,17 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
204 dimension_updated, 'END\n']))
205 else:
206 chart.penalty += 1
207 +
208 + if not charts_updated:
209 + self.debug('none of the charts have been updated')
210 +
211 return charts_updated
212
213 def manage_retries(self):
214 self._runtime_counters.RETRIES += 1
215 if self._runtime_counters.RETRIES >= self._runtime_counters.RETRIES_MAX:
216 - self.error(STOP_MSG.format(retries_max=self._runtime_counters.RETRIES_MAX))
216 + self.error('stopped after {retries_max} data '
217 + 'collection failures in a row'.format(retries_max=self._runtime_counters.RETRIES_MAX))
218 return False
219 return True
220
@@ -223,8 +224,8 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
224 # sleep() is interruptable
225 while job.is_sleep_time():
226 sleep_time = job.NEXT_RUN - job.START_RUN
226 - self.debug(SLEEP_MSG.format(sleep_time=sleep_time,
227 - freq=job.FREQ))
227 + self.debug('sleeping for {sleep_time} to reach frequency of {freq} sec'.format(sleep_time=sleep_time,
228 + freq=job.FREQ))
229 sleep(sleep_time)
230 job.START_RUN = time()
231
python.d/python_modules/bases/charts.py
+17 -12
@@ -39,7 +39,7 @@ def create_runtime_chart(func):
39 return wrapper
40
41
42 -class ReAddingError(Exception):
42 +class DuplicateError(Exception):
43 pass
44
45
@@ -73,8 +73,11 @@ class Charts:
73 def __delitem__(self, key):
74 del self.charts[key]
75
76 - def empty(self):
77 - return not bool(self.charts)
76 + def __bool__(self):
77 + return bool(self.charts)
78 +
79 + def __nonzero__(self):
80 + return self.__bool__()
81
82 def penalty_exceeded(self, penalty_max):
83 """
@@ -91,7 +94,7 @@ class Charts:
94 params = [self.job_name()] + params
95 chart_id = params[1]
96 if chart_id in self.charts:
94 - raise ReAddingError('{chart} already in charts'.format(chart=chart_id))
97 + raise DuplicateError('{chart} already in charts'.format(chart=chart_id))
98 else:
99 new_chart = Chart(params)
100 new_chart.params['update_every'] = self.update_every
@@ -106,11 +109,12 @@ class Chart:
109 """
110 :param params: <list>
111 """
109 - if not (params and isinstance(params, list)):
110 - raise ValueError('Chart params must be a not empty list')
112 + if not (params and isinstance(params, list) and len(params) >= 8):
113 + raise ValueError('Chart params must be a list with 7 items')
114
115 self.params = dict(zip(CHART_PARAMS, (p or str() for p in params)))
113 - self.name = '.'.join([self.params['type'], self.params['id']])
116 + self.name = '{type}.{id}'.format(type=self.params['type'],
117 + id=self.params['id'])
118 if self.params.get('chart_type') not in CHART_TYPES:
119 self.params['chart_type'] = 'absolute'
120
@@ -135,8 +139,8 @@ class Chart:
139 :return:
140 """
141 if dimension[0] in [repr(d) for d in self.dimensions]:
138 - raise ReAddingError('{dimension} already in {chart} dimensions'.format(dimension=dimension[0],
139 - chart=self.name))
142 + raise DuplicateError('{dimension} already in {chart} dimensions'.format(dimension=dimension[0],
143 + chart=self.name))
144 self.dimensions.append(Dimension(dimension))
145
146 def add_dimension_and_push_chart(self, dimension):
@@ -145,8 +149,8 @@ class Chart:
149 :return:
150 """
151 if dimension[0] in [repr(d) for d in self.dimensions]:
148 - raise ReAddingError('{dimension} already in {chart} dimensions'.format(dimension=dimension[0],
149 - chart=self.name))
152 + raise DuplicateError('{dimension} already in {chart} dimensions'.format(dimension=dimension[0],
153 + chart=self.name))
154 dimension = Dimension(dimension)
155 self.dimensions.append(dimension)
156 safe_print(self.create(dimension))
@@ -185,7 +189,8 @@ class Dimension:
189 raise ValueError('Dimension params must be a not empty list')
190
191 self.params = dict(zip(DIMENSION_PARAMS, (p or str() for p in params)))
188 - self.params['name'] = self.params.get('name') or self.params.get('id')
192 + self.params['name'] = self.params.get('name') or self.params['id']
193 +
194 if self.params.get('algorithm') not in DIMENSION_ALGORITHMS:
195 self.params['algorithm'] = 'absolute'
196 if not str(self.params.get('multiplier')).isdigit():