brynq-sdk-task-scheduler 1.1.4__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq_sdk_task_scheduler
3
- Version: 1.1.4
3
+ Version: 1.2.0
4
4
  Summary: Code to execute tasks in BrynQ.com with the task scheduler
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -32,6 +32,9 @@ class TaskScheduler(BrynQ):
32
32
  self.es = Elastic()
33
33
  self.mysql = MySQL()
34
34
  self.email_after_errors = email_after_errors
35
+ self.customer_db = self.mysql.database
36
+ self.customer_id = self.mysql.raw_query(f'SELECT id FROM sc.customers WHERE dbname = \'{self.customer_db}\'')[0][0]
37
+ self.partner_id = os.getenv('PARTNER_ID').lower().replace(' ', '_') if os.getenv('PARTNER_ID') else 'brynq'
35
38
  self.task_id = task_id
36
39
  self.loglevel = loglevel
37
40
  self.started_at = datetime.datetime.now()
@@ -42,7 +45,6 @@ class TaskScheduler(BrynQ):
42
45
  # If the task is started locally, the parameters should be set locally
43
46
  else:
44
47
  self.started_local = True
45
- self.customer_db = 'placeholder'
46
48
  self.run_id = int(round(time.time() * 100000))
47
49
  print(self.task_id, self.run_id)
48
50
  self.error_count = 0
@@ -55,7 +57,9 @@ class TaskScheduler(BrynQ):
55
57
  self.task_manual_started = self.check_if_task_manual_started()
56
58
 
57
59
  # Creates Elasticsearch index and data view if not exists
58
- self.es.initialize_customer()
60
+ self.es_index = f"task_execution_log_{self.customer_db}_{self.started_at.strftime('%Y_%m')}"
61
+ self.es.create_index(index_name=self.es_index)
62
+ self.es.create_data_view(space_name='interfaces', view_name=f'task_execution_log_{self.customer_db}', name=f'Task execution log {self.customer_db}', time_field='started_at')
59
63
 
60
64
  # Start the task and setup the data in the database
61
65
  self.start_task()
@@ -71,6 +75,14 @@ class TaskScheduler(BrynQ):
71
75
  key_count += self.__count_keys(value) # Recursively count keys in nested dictionaries
72
76
  return key_count
73
77
 
78
+ def __get_caller_info(self):
79
+ stack = inspect.stack()
80
+ caller_frame = stack[2][0]
81
+ file_name = caller_frame.f_code.co_filename
82
+ line_number = caller_frame.f_lineno
83
+ function_name = stack[2][3]
84
+ return file_name, line_number, function_name
85
+
74
86
  def create_task_execution_steps(self, step_details: list):
75
87
  """
76
88
  Check if the given steps already exists in the task_execution_steps table. If not, update or insert the values in the table
@@ -158,7 +170,8 @@ class TaskScheduler(BrynQ):
158
170
  if loglevel not in allowed_loglevels:
159
171
  raise Exception('You\'ve entered a not allowed loglevel. Choose one of: {}'.format(allowed_loglevels))
160
172
 
161
- # Handling different data types and preparing extra payload information based on the data type
173
+ # For Elastic, we need to have the data in JSON format. Handling different data types and preparing extra payload information based on the data type
174
+ # If the data is just a series, count rows, columns and cells
162
175
  if isinstance(data, pd.Series):
163
176
  dataframe = pd.DataFrame(data).T
164
177
  extra_payload = {
@@ -168,6 +181,7 @@ class TaskScheduler(BrynQ):
168
181
  }
169
182
  if not full_extract:
170
183
  extra_payload['payload'] = dataframe.to_json(orient='records')
184
+ # If the data is a list, count rows, columns and cells
171
185
  elif isinstance(data, dict):
172
186
  records = self.__count_keys(data)
173
187
  extra_payload = {
@@ -185,6 +199,7 @@ class TaskScheduler(BrynQ):
185
199
  }
186
200
  if not full_extract:
187
201
  extra_payload['payload'] = data.to_json(orient='records')
202
+ # If the data is a response from an URL request, also store all the information about the URL request.
188
203
  elif isinstance(data, requests.Response):
189
204
  records = 1
190
205
  if data.request.body is not None:
@@ -217,41 +232,37 @@ class TaskScheduler(BrynQ):
217
232
  elif data is not None and full_extract is False:
218
233
  extra_payload['full_load'] = False
219
234
 
220
- # Preparing the primary payload with log details
235
+ # Get the linenumber from where the logline is executed.
236
+ file_name, line_number, function_name = self.__get_caller_info()
237
+
238
+ # Put everything together in the payload for ElasticSearch and send it
221
239
  payload = {
222
- 'reload_id': self.run_id,
223
240
  'task_id': self.task_id,
224
- 'customer_id': os.getenv('BRYNQ_SUBDOMAIN').lower().replace(' ', '_'),
241
+ 'reload_id': self.run_id,
225
242
  'started_at': datetime.datetime.now().isoformat(),
226
- 'loglevel': loglevel,
243
+ 'partner_id': self.partner_id,
244
+ 'customer_id': self.customer_id,
245
+ 'customer': os.getenv('BRYNQ_CUSTOMER_NAME').lower().replace(' ', '_'),
246
+ 'file_name': file_name,
247
+ 'function_name': function_name,
248
+ 'line_number': line_number,
249
+ 'task_loglevel': self.loglevel,
250
+ 'line_loglevel': loglevel,
227
251
  'message': message
228
252
  }
229
253
  payload.update(extra_payload)
254
+ self.es.post_document(index_name=self.es_index, document=payload)
230
255
 
231
- # Sending the payload to ElasticSearch
232
- self.es.task_execution_log(payload)
233
-
234
- # Get the linenumber from where the logline is executed. Get the stacktrace of this action, jump 1 file up and pick then the linenumber (second item)
235
- linenumber = inspect.getouterframes(inspect.currentframe())[1][2]
236
- # Write the logline to the database, depends on the chosen loglevel in the task
237
- print('{} at line: {}'.format(message, linenumber))
256
+ # Write the logline to the MYSQL database, depends on the chosen loglevel in the task
257
+ print('{} at line: {}'.format(message, line_number))
238
258
  # Remove quotes from message since these break the query
239
259
  message = re.sub("[']", '', message)
240
- timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
241
- information = {
242
- 'reload_id': self.run_id,
243
- 'task_id': self.task_id,
244
- 'log_level': loglevel,
245
- 'line_number': linenumber,
246
- 'message': message,
247
- 'created_at': timestamp
248
- }
249
260
  if self.loglevel == 'DEBUG':
250
261
  # Count the errors
251
262
  if loglevel == 'ERROR' or loglevel == 'CRITICAL':
252
263
  self.error_count += 1
253
264
  return self.mysql.raw_query(
254
- "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), linenumber, message), insert=True)
265
+ "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), line_number, message), insert=True)
255
266
  return self.mysql.update(table='task_execution_log',
256
267
  columns=['reload_id', 'task_id', 'log_level', 'created_at', 'line_number', 'message'],
257
268
  values=[self.run_id, self.task_id, loglevel, datetime.datetime.now(), linenumber, message])
@@ -260,15 +271,15 @@ class TaskScheduler(BrynQ):
260
271
  if loglevel == 'ERROR' or loglevel == 'CRITICAL':
261
272
  self.error_count += 1
262
273
  return self.mysql.raw_query(
263
- "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), linenumber, message), insert=True)
274
+ "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), line_number, message), insert=True)
264
275
  elif self.loglevel == 'ERROR' and (loglevel == 'ERROR' or loglevel == 'CRITICAL'):
265
276
  self.error_count += 1
266
277
  return self.mysql.raw_query(
267
- "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), linenumber, message), insert=True)
278
+ "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), line_number, message), insert=True)
268
279
  elif self.loglevel == 'CRITICAL' and loglevel == 'CRITICAL':
269
280
  self.error_count += 1
270
281
  return self.mysql.raw_query(
271
- "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), linenumber, message), insert=True)
282
+ "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, '{}', '{}', {}, '{}')".format(self.run_id, self.task_id, loglevel, datetime.datetime.now(), line_number, message), insert=True)
272
283
 
273
284
  def update_execution_step(self, step_number: int):
274
285
  """
@@ -290,24 +301,32 @@ class TaskScheduler(BrynQ):
290
301
  :param started_at: Give the time the task is started
291
302
  :return: nothing
292
303
  """
304
+ # Format error to a somewhat readable format
305
+ exc_type, exc_obj, exc_tb = sys.exc_info()
306
+ error = str(e)[:400].replace('\'', '').replace('\"', '') + ' | Line: {}'.format(exc_tb.tb_lineno)
307
+
308
+ # Get the linenumber from where the logline is executed.
309
+ file_name, line_number, function_name = self.__get_caller_info()
293
310
 
294
- # Preparing the primary payload with error details for upload to elastic
311
+ # Preparing the primary payload with error details for upload to elastic and send it
295
312
  payload = {
296
- 'reload_id': self.run_id,
297
313
  'task_id': self.task_id,
298
- 'customer_id': os.getenv('BRYNQ_SUBDOMAIN').lower().replace(' ', '_'),
314
+ 'reload_id': self.run_id,
299
315
  'started_at': datetime.datetime.now().isoformat(),
300
- 'loglevel': 'CRITICAL',
316
+ 'partner_id': self.partner_id,
317
+ 'customer_id': self.customer_id,
318
+ 'customer': os.getenv('BRYNQ_CUSTOMER_NAME').lower().replace(' ', '_'),
319
+ 'file_name': file_name,
320
+ 'function_name': function_name,
321
+ 'line_number': line_number,
322
+ 'task_loglevel': self.loglevel,
323
+ 'line_loglevel': 'CRITICAL',
301
324
  'message': str(e),
302
325
  'traceback': traceback.format_exc()
303
326
  }
327
+ self.es.post_document(index_name=self.es_index, document=payload)
304
328
 
305
- # Sending the payload to ElasticSearch
306
- self.es.task_execution_log(payload)
307
329
 
308
- # Format error to a somewhat readable format
309
- exc_type, exc_obj, exc_tb = sys.exc_info()
310
- error = str(e)[:400].replace('\'', '').replace('\"', '') + ' | Line: {}'.format(exc_tb.tb_lineno)
311
330
  # Get scheduler task details for logging
312
331
  task_details = \
313
332
  self.mysql.select('task_scheduler, data_interfaces', 'data_interfaces.docker_image, data_interfaces.runfile_path', 'WHERE task_scheduler.data_interface_id = data_interfaces.id AND task_scheduler.id = {}'.format(self.task_id))[0]
@@ -320,15 +339,6 @@ class TaskScheduler(BrynQ):
320
339
  ['IDLE', datetime.datetime.now(), 'Failed', 0],
321
340
  'WHERE `id` = {}'.format(self.task_id))
322
341
  # Log to database
323
- timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
324
- information = {
325
- 'reload_id': self.run_id,
326
- 'task_id': self.task_id,
327
- 'log_level': 'CRITICAL',
328
- 'line_number': exc_tb.tb_lineno,
329
- 'message': error,
330
- 'created_at': timestamp
331
- }
332
342
  self.mysql.raw_query(
333
343
  "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, 'CRITICAL', '{}', {}, '{}')".format(self.run_id,
334
344
  self.task_id,
@@ -353,15 +363,6 @@ class TaskScheduler(BrynQ):
353
363
 
354
364
  raise Exception(error)
355
365
  else:
356
- timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
357
- information = {
358
- 'reload_id': self.run_id,
359
- 'task_id': self.task_id,
360
- 'log_level': 'CRITICAL',
361
- 'line_number': exc_tb.tb_lineno,
362
- 'message': error,
363
- 'created_at': timestamp
364
- }
365
366
  self.mysql.raw_query(
366
367
  "INSERT INTO `task_execution_log` (reload_id, task_id, log_level, created_at, line_number, message) VALUES ({}, {}, 'CRITICAL', '{}', {}, '{}')".format(self.run_id,
367
368
  self.task_id,
@@ -442,11 +443,9 @@ class TaskScheduler(BrynQ):
442
443
  for i in email_to:
443
444
  email_list.append({'name': 'BrynQ User', 'mail': i.strip()})
444
445
  # Set the content of the mail and all other stuff
445
- task = self.mysql.select(table='task_scheduler', selection='title', filter=f'WHERE id = {self.task_id}')[0][
446
- 0]
446
+ task = self.mysql.select(table='data_interfaces', selection='title', filter=f'WHERE id = {self.task_id}')[0][0]
447
447
  finished_at = \
448
- self.mysql.select(table='task_scheduler', selection='last_reload', filter=f'WHERE id = {self.task_id}')[0][
449
- 0]
448
+ self.mysql.select(table='task_scheduler', selection='last_reload', filter=f'WHERE data_interface_id = {self.task_id}')[0][0]
450
449
  if failed:
451
450
  subject = f'Task \'{task}\' has failed'
452
451
  content = f'Task \'{task}\' with task ID \'{self.task_id}\' failed during its last run and was stopped at {finished_at}. ' \
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq-sdk-task-scheduler
3
- Version: 1.1.4
3
+ Version: 1.2.0
4
4
  Summary: Code to execute tasks in BrynQ.com with the task scheduler
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -3,7 +3,7 @@ from setuptools import setup
3
3
 
4
4
  setup(
5
5
  name='brynq_sdk_task_scheduler',
6
- version='1.1.4',
6
+ version='1.2.0',
7
7
  description='Code to execute tasks in BrynQ.com with the task scheduler',
8
8
  long_description='Code to execute tasks in the BrynQ.com platform with the task scheduler',
9
9
  author='BrynQ',