def __init__(self, prefix, instance: Task, initial): super().__init__() self.fields['name'].initial = instance.name logs = list() # on this stage it was quite hard to implement proper formatting in templates # so putting some html/js right here. # TODO: Refactor, put formatting to the templates # Main problem is that this form's template uses some base template which replaces \n with <br /> for record in instance.get_task_log_from_elasticsearch(): color = 'green' if record.log_level == 'WARN': color = 'yellow' elif record.log_level == 'ERROR': color = 'red' if not record.timestamp: ts = '' else: ts = record.timestamp.strftime('%Y-%m-%d %H:%M:%S') level = record.log_level or 'INFO' message = record.message if message and '\n' in message: message = '<br />' + message log_add = f'<b><span style="color: {color}">{level}</span> {ts} | {record.task_name or "no task"} |</b> ' \ f'{message}' logs.append(log_add) if record.stack_trace: # Adding JS to toggle stack trace showing/hiding stack = record.stack_trace.replace('\n', '<br />') uid = str(fast_uuid()) uid_toggle = uid + '_toggle' show_hide = f'''e = document.getElementById('{uid}'); e.style.display = e.style.display === 'block' ? 'none' : 'block'; document.getElementById('{uid_toggle}').innerText = e.style.display === 'block' ? '[-] Stack trace:' : '[+] Stack trace'; '''.replace('\n', '') logs.append( f'<a id="{uid_toggle}" onclick="{show_hide}">[+] Stack trace:</a>' ) logs.append( f'<div id="{uid}" style="display: none; border-left: 1px solid grey; padding-left: 16px">' f'{stack}</div>') self.fields['log'].initial = '\n'.join(logs)
def get_task_detail(cls, task: Task) -> TaskRecord: reason = f'is started at {task.date_work_start} and not finished yet' if task.status == PENDING else 'is failed' r = TaskRecord(task.pk, task.name, reason, task.status, task.date_work_start or task.date_start, task.date_done or task.own_date_done, task.user_id) for record in task.get_task_log_from_elasticsearch(): r.kibana_ref = kibana_root_url(record.record_id, record.file_index, add_protocol=False) if not hasattr(record, 'stack_trace') or not hasattr(record, 'message') \ or record.log_level != 'ERROR': continue r.error_message = record.message r.stack_trace = record.stack_trace break return r
def __init__(self, prefix, instance: Task, initial): super().__init__() display_name = instance.display_name or instance.name if display_name != instance.name: display_name += f' ({instance.name})' if instance.status != SUCCESS: display_name += f' STATUS: {instance.status}' if instance.progress < 100: display_name += f' ({instance.progress}%)' self.fields['task'].initial = display_name self.fields['parents'].initial = '' self.fields['child_tasks'].initial = '' logs = list() # on this stage it was quite hard to implement proper formatting in templates # so putting some html/js right here. # TODO: Refactor, put formatting to the templates # list ancestors (parent tasks) up to the root parents_markup = [] this_task = instance while this_task.parent_task_id: parent = this_task.parent_task task_name = parent.display_name or parent.name url = reverse('task:task-detail', args=[parent.pk]) color = self.COLOR_BY_STATUS.get( parent.status) or self.COLOR_BY_STATUS['default'] link_name = task_name if parent.progress == 100 else f'{task_name} ({parent.progress}%)' parents_markup.append( f'<a style="{color}" href="{url}">{link_name}</a>') this_task = this_task.parent_task markup = '' if parents_markup: markup = ' <- '.join(parents_markup) self.fields['parents'].initial = markup # list child tasks child_query = Task.objects.filter(parent_task_id=instance.pk) children_count = child_query.count() children = list( child_query.values_list('pk', 'name', 'display_name', 'status', 'progress')[:30]) children_markup = [] for pk, name, display_name, status, progress in children: url = reverse('task:task-detail', args=[pk]) color = self.COLOR_BY_STATUS.get( status) or self.COLOR_BY_STATUS['default'] task_name = display_name or name link_name = task_name if progress == 100 else f'{task_name} ({progress}%)' children_markup.append( f'<a style="{color}" href="{url}">{link_name}</a>') if children_count > len(children): children_markup.append( f' ... and {children_count - len(children)} more') self.fields['child_tasks'].initial = ', '.join(children_markup) # Main problem is that this form's template uses some base template which replaces \n with <br /> for record in instance.get_task_log_from_elasticsearch(): color = 'green' if record.log_level == 'WARN': color = 'yellow' elif record.log_level == 'ERROR': color = 'red' if not record.timestamp: ts = '' else: ts = record.timestamp.strftime('%Y-%m-%d %H:%M:%S') level = record.log_level or 'INFO' message = record.message if message and '\n' in message: message = '<br />' + message log_add = f'<b><span style="color: {color}">{level}</span> {ts} | {record.task_name or "no task"} |</b> ' \ f'{message}' logs.append(log_add) if record.stack_trace: # Adding JS to toggle stack trace showing/hiding stack = record.stack_trace.replace('\n', '<br />') uid = str(fast_uuid()) uid_toggle = uid + '_toggle' show_hide = f'''e = document.getElementById('{uid}'); e.style.display = e.style.display === 'block' ? 'none' : 'block'; document.getElementById('{uid_toggle}').innerText = e.style.display === 'block' ? '[-] Stack trace:' : '[+] Stack trace'; '''.replace('\n', '') logs.append( f'<a id="{uid_toggle}" onclick="{show_hide}">[+] Stack trace:</a>' ) logs.append( f'<div id="{uid}" style="display: none; border-left: 1px solid grey; padding-left: 16px">' f'{stack}</div>') self.fields['log'].initial = '\n'.join(logs)
def __init__(self, prefix, instance: Task, initial): super().__init__() self.fields['name'].initial = instance.name self.fields['log'].initial = instance.get_task_log_from_elasticsearch()
def __init__(self, prefix, instance: Task, initial): super().__init__() display_name = instance.display_name or instance.name if display_name != instance.name: display_name += f' ({instance.name})' if instance.status != SUCCESS: display_name += f' STATUS: {instance.status}' if instance.progress < 100: display_name += f' ({instance.progress}%)' self.fields['task'].initial = display_name self.fields['parents'].initial = '' self.fields['child_tasks'].initial = '' logs = list() # type: List[str] # on this stage it was quite hard to implement proper formatting in templates # so putting some html/js right here. # TODO: Refactor, put formatting to the templates # list ancestors (parent tasks) up to the root parents_markup = [] this_task = instance while this_task.parent_task_id: parent = this_task.parent_task task_name = parent.display_name or parent.name url = reverse('task:task-detail', args=[parent.pk]) color = self.COLOR_BY_STATUS.get(parent.status) or self.COLOR_BY_STATUS['default'] link_name = task_name if parent.progress == 100 else f'{task_name} ({parent.progress}%)' parents_markup.append(f'<a style="{color}" href="{url}">{link_name}</a>') this_task = this_task.parent_task markup = '' if parents_markup: markup = ' <- '.join(parents_markup) self.fields['parents'].initial = markup # list child tasks child_query = Task.objects.filter(parent_task_id=instance.pk) children_count = child_query.count() children = list(child_query.values_list( 'pk', 'name', 'display_name', 'status', 'progress')[:30]) children_markup = [] for pk, name, display_name, status, progress in children: url = reverse('task:task-detail', args=[pk]) color = self.COLOR_BY_STATUS.get(status) or self.COLOR_BY_STATUS['default'] task_name = display_name or name link_name = task_name if progress == 100 else f'{task_name} ({progress}%)' children_markup.append(f'<a style="{color}" href="{url}">{link_name}</a>') if children_count > len(children): children_markup.append(f' ... and {children_count - len(children)} more') self.fields['child_tasks'].initial = ', '.join(children_markup) if this_task.result and 'exc_type' in this_task.result: ex_module = this_task.result.get('exc_module') or '-' ex_message = this_task.result.get('exc_message') or '-' msg = f'<b><span style="color:red">ERROR</span> {this_task.result["exc_type"]} ' + \ f'in {ex_module}:\n{ex_message}' logs.append(msg) # Main problem is that this form's template uses some base template which replaces \n with <br /> should_search_errors = this_task.status in {FAILURE, REVOKED} or \ this_task.own_status in {FAILURE, REVOKED} all_records = instance.get_task_log_from_elasticsearch(should_search_errors) task_records = [r for r in all_records if r.task_name] genr_records = [r for r in all_records if not r.task_name] for record in task_records: color = self.get_task_record_color(record) ts = record.timestamp.strftime('%Y-%m-%d %H:%M:%S') if record.timestamp else '' level = record.log_level or 'INFO' message = record.message or '' message = '<br />' + message if '\n' in message else message log_add = f'<b><span style="color: {color}">{level}</span> {ts} | {record.task_name or "no task"} |</b> ' \ f'{message}' logs.append(log_add) if record.stack_trace: # Adding JS to toggle stack trace showing/hiding stack = record.stack_trace.replace('<', '<').replace( '>', '>').replace('\n', '<br />') self.render_collapsible_block(logs, stack, 'Stack trace') # show system-wide errors in collapsible block if genr_records: logs.append(f'<br/><h4>{len(genr_records)} error(s) also occurred after completing the task</h4>') inner_block = '' for record in genr_records: color = self.get_task_record_color(record) ts = record.timestamp.strftime('%Y-%m-%d %H:%M:%S') if record.timestamp else '' level = record.log_level or 'INFO' message = record.message or '' message = '<br />' + message if '\n' in message else message log_add = f'<b><span style="color: {color}">{level}</span> {ts} </b> ' \ f'{message}<br/>' inner_block += log_add self.render_collapsible_block(logs, inner_block, 'System-wide errors') self.fields['log'].initial = '\n'.join(logs)