Merge pull request #16653 from rmehta/error-log-ref

feat(minor): Add document reference to Error Log and doc.log_error
This commit is contained in:
Rushabh Mehta 2022-04-20 15:54:59 +05:30 committed by GitHub
commit 78bddb4127
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 156 additions and 198 deletions

View file

@ -2067,25 +2067,36 @@ def logger(
)
def log_error(message=None, title=_("Error")):
def log_error(title=None, message=None, reference_doctype=None, reference_name=None):
"""Log error to Error Log"""
# AI ALERT:
# Parameter ALERT:
# the title and message may be swapped
# the better API for this is log_error(title, message), and used in many cases this way
# this hack tries to be smart about whats a title (single line ;-)) and fixes it
traceback = None
if message:
if "\n" in title:
error, title = title, message
if "\n" in title: # traceback sent as title
traceback, title = title, message
else:
error = message
else:
error = get_traceback()
traceback = message
return get_doc(dict(doctype="Error Log", error=as_unicode(error), method=title)).insert(
ignore_permissions=True
)
if not traceback:
traceback = get_traceback()
if not title:
title = "Error"
return get_doc(
dict(
doctype="Error Log",
error=as_unicode(traceback),
method=title,
reference_doctype=reference_doctype,
reference_name=reference_name,
)
).insert(ignore_permissions=True)
def get_desk_link(doctype, name):

View file

@ -189,7 +189,7 @@ class AutoRepeat(Document):
if self.notify_by_email and self.recipients:
self.send_notification(new_doc)
except Exception:
error_log = frappe.log_error(frappe.get_traceback(), _("Auto Repeat Document Creation Failure"))
error_log = self.log_error("Auto repeat failed")
self.disable_auto_repeat()

View file

@ -5,7 +5,6 @@ import json
import frappe
from frappe.desk.notifications import clear_notifications, delete_notification_count_for
from frappe.model.document import Document
common_default_keys = ["__default", "__global"]

View file

@ -450,8 +450,7 @@ def get_contacts(email_strings: List[str], auto_create_contact=False) -> List[st
contact.insert(ignore_permissions=True)
contact_name = contact.name
except Exception:
traceback = frappe.get_traceback()
frappe.log_error(traceback)
contact.log_error("Unable to add contact")
if contact_name:
contacts.append(contact_name)

View file

@ -248,7 +248,7 @@ def mark_email_as_seen(name: str = None):
frappe.db.commit() # nosemgrep: this will be called in a GET request
except Exception:
frappe.log_error(frappe.get_traceback())
frappe.log_error("Unable to mark as seen", None, "Communication", name)
finally:
frappe.response.update(

View file

@ -113,7 +113,7 @@ def start_import(data_import):
except Exception:
frappe.db.rollback()
data_import.db_set("status", "Error")
frappe.log_error(title=data_import.name)
data_import.log_error("Data import failed")
finally:
frappe.flags.in_import = False

View file

@ -1,148 +1,76 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "",
"beta": 0,
"creation": "2013-01-16 13:09:40",
"custom": 0,
"description": "Log of Scheduler Errors",
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 0,
"engine": "MyISAM",
"actions": [],
"creation": "2013-01-16 13:09:40",
"doctype": "DocType",
"document_type": "System",
"engine": "MyISAM",
"field_order": [
"seen",
"method",
"error",
"reference_doctype",
"reference_name"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "seen",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Seen",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"default": "0",
"fieldname": "seen",
"fieldtype": "Check",
"hidden": 1,
"label": "Seen"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "method",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Title",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "method",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "error",
"fieldtype": "Code",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Error",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
"fieldname": "error",
"fieldtype": "Code",
"label": "Error",
"read_only": 1
},
{
"fieldname": "reference_doctype",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Reference DocType",
"options": "DocType",
"search_index": 1
},
{
"fieldname": "reference_name",
"fieldtype": "Data",
"label": "Reference Name"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-warning-sign",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2021-10-25 12:21:44.292471",
"modified_by": "Administrator",
"module": "Core",
"name": "Error Log",
"owner": "Administrator",
],
"icon": "fa fa-warning-sign",
"idx": 1,
"links": [],
"modified": "2022-04-18 17:25:47.406873",
"modified_by": "Administrator",
"module": "Core",
"name": "Error Log",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_order": "ASC",
"track_seen": 0
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "ASC",
"states": [],
"title_field": "method"
}

View file

@ -9,4 +9,8 @@ import frappe
class TestErrorLog(unittest.TestCase):
pass
def test_error_log(self):
"""let's do an error log on error log?"""
doc = frappe.new_doc("Error Log")
error = doc.log_error("This is an error")
self.assertEqual(error.doctype, "Error Log")

View file

@ -1043,7 +1043,7 @@ def attach_files_to_document(doc, event):
):
return
frappe.get_doc(
file_doc = frappe.get_doc(
doctype="File",
file_url=value,
attached_to_name=doc.name,
@ -1052,4 +1052,4 @@ def attach_files_to_document(doc, event):
folder="Home/Attachments",
).insert()
except Exception:
frappe.log_error(title=_("Error Attaching File"))
file_doc.log_error("Error Attaching File")

View file

@ -47,7 +47,7 @@ def run_background(prepared_report):
instance.save(ignore_permissions=True)
except Exception:
frappe.log_error(frappe.get_traceback())
report.log_error("Prepared report failed")
instance = frappe.get_doc("Prepared Report", prepared_report)
instance.status = "Error"
instance.error_message = frappe.get_traceback()

View file

@ -265,7 +265,7 @@ class User(Document):
except frappe.OutgoingEmailError:
# email server not set, don't send email
frappe.log_error(frappe.get_traceback())
self.log_error("Unable to send new password notification")
@Document.hook
def validate_reset_password(self):

View file

@ -338,7 +338,7 @@ def get_desktop_page(page):
"onboardings": workspace.onboardings,
}
except DoesNotExistError:
frappe.log_error(frappe.get_traceback())
frappe.log_error("Workspace Missing")
return {}
@ -472,7 +472,7 @@ def save_new_widget(doc, page, blocks, new_widgets):
""".format(
page, json_config, e
)
frappe.log_error(log, _("Could not save customization"))
doc.log_error("Could not save customization", log)
return False
return True

View file

@ -20,7 +20,7 @@ class NotificationLog(Document):
try:
send_notification_email(self)
except frappe.OutgoingEmailError:
frappe.log_error(message=frappe.get_traceback(), title=_("Failed to send notification email"))
self.log_error(_("Failed to send notification email"))
def get_permission_query_conditions(for_user):

View file

@ -1,7 +1,7 @@
{
"actions": [
{
"action": "app/console-log",
"action": "/app/console-log",
"action_type": "Route",
"label": "Logs"
},
@ -86,7 +86,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2022-04-09 16:35:32.345542",
"modified": "2022-04-15 14:15:58.398590",
"modified_by": "Administrator",
"module": "Desk",
"name": "System Console",
@ -106,4 +106,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View file

@ -314,7 +314,7 @@ def get_prepared_report_result(report, filters, dn="", user=None):
latest_report_data = {"columns": columns, "result": data}
except Exception:
frappe.log_error(frappe.get_traceback())
doc.log_error("Prepared report failed")
frappe.delete_doc("Prepared Report", doc.name)
frappe.db.commit()
doc = None

View file

@ -255,7 +255,9 @@ def send_daily():
try:
auto_email_report.send()
except Exception as e:
frappe.log_error(e, _("Failed to send {0} Auto Email Report").format(auto_email_report.name))
auto_email_report.log_error(
"Failed to send {0} Auto Email Report".format(auto_email_report.name)
)
def send_monthly():

View file

@ -473,7 +473,7 @@ class EmailAccount(Document):
frappe.db.rollback()
except Exception:
frappe.db.rollback()
frappe.log_error(title="EmailAccount.receive")
self.log_error(title="EmailAccount.receive")
if self.use_imap:
self.handle_bad_emails(mail.uid, mail.raw_message, frappe.get_traceback())
exceptions.append(frappe.get_traceback())
@ -521,7 +521,7 @@ class EmailAccount(Document):
# close connection to mailserver
email_server.logout()
except Exception:
frappe.log_error(title=_("Error while connecting to email account {0}").format(self.name))
self.log_error(title=_("Error while connecting to email account {0}").format(self.name))
return []
return mails
@ -667,7 +667,7 @@ class EmailAccount(Document):
try:
email_server = self.get_incoming_server(in_receive=True)
except Exception:
frappe.log_error(title=_("Error while connecting to email account {0}").format(self.name))
self.log_error("Email Connection Error")
if not email_server:
return
@ -679,7 +679,7 @@ class EmailAccount(Document):
message = safe_encode(message)
email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message)
except Exception:
frappe.log_error(title="EmailAccount.append_email_to_sent_folder")
self.log_error("Unable to add to Sent folder")
@frappe.whitelist()

View file

@ -198,10 +198,7 @@ class SendMailContext:
traceback_string = "".join(traceback.format_tb(exc_tb))
traceback_string += f"\n Queue Name: {self.queue_doc.name}"
if self.is_background_task:
frappe.log_error(title="frappe.email.queue.flush", message=traceback_string)
else:
frappe.log_error(message=traceback_string)
self.queue_doc.log_error("Email sending failed", traceback_string)
@property
def smtp_session(self):
@ -625,11 +622,11 @@ class QueueBuilder:
mail_to_string = cstr(mail.as_string())
except frappe.InvalidEmailAddressError:
# bad Email Address - don't add to queue
frappe.log_error(
"Invalid Email ID Sender: {0}, Recipients: {1}, \nTraceback: {2} ".format(
self.log_error(
title="Invalid email address",
message="Invalid email address Sender: {0}, Recipients: {1}, \nTraceback: {2} ".format(
self.sender, ", ".join(self.final_recipients()), traceback.format_exc()
),
"Email Not Sent",
)
return

View file

@ -329,19 +329,17 @@ def send_scheduled_email():
pluck="name",
)
for newsletter in scheduled_newsletter:
for newsletter_name in scheduled_newsletter:
try:
frappe.get_doc("Newsletter", newsletter).queue_all()
newsletter = frappe.get_doc("Newsletter", newsletter_name)
newsletter.queue_all()
except Exception:
frappe.db.rollback()
# wasn't able to send emails :(
frappe.db.set_value("Newsletter", newsletter, "email_sent", 0)
message = (
f"Newsletter {newsletter} failed to send" "\n\n" f"Traceback: {frappe.get_traceback()}"
)
frappe.log_error(title="Send Newsletter", message=message)
frappe.db.set_value("Newsletter", newsletter_name, "email_sent", 0)
newsletter.log_error("Failed to send newsletter")
if not frappe.flags.in_test:
frappe.db.commit()

View file

@ -141,7 +141,7 @@ def get_context(context):
self.create_system_notification(doc, context)
except:
frappe.log_error(title="Failed to send notification", message=frappe.get_traceback())
self.log_error("Failed to send Notification")
if self.set_property_after_alert:
allow_update = True
@ -168,7 +168,7 @@ def get_context(context):
doc.save(ignore_permissions=True)
doc.flags.in_notification_update = False
except Exception:
frappe.log_error(title="Document update failed", message=frappe.get_traceback())
self.log_error("Document update failed")
def create_system_notification(self, doc, context):
subject = self.subject
@ -433,7 +433,7 @@ def evaluate_alert(doc, alert, event):
if event == "Value Change" and not doc.is_new():
if not frappe.db.has_column(doc.doctype, alert.value_changed):
alert.db_set("enabled", 0)
frappe.log_error("Notification {0} has been disabled due to missing field".format(alert.name))
alert.log_error("Notification {0} has been disabled due to missing field".format(alert.name))
return
doc_before_save = doc.get_doc_before_save()

View file

@ -170,7 +170,7 @@ def flush(from_test=False):
is_background_task = not from_test
func(email_queue_name=row.name, is_background_task=is_background_task)
except Exception:
frappe.log_error()
frappe.get_doc("Email Queue", row.name).log_error()
def get_queue():

View file

@ -123,7 +123,7 @@ class EmailServer:
except _socket.error:
# log performs rollback and logs error in Error Log
frappe.log_error("receive.connect_pop")
self.log_error("POP: Unable to connect")
# Invalid mail server -- due to refusing connection
frappe.msgprint(_("Invalid Mail Server. Please rectify and try again."))
@ -306,7 +306,7 @@ class EmailServer:
else:
# log performs rollback and logs error in Error Log
frappe.log_error("receive.get_messages", self.make_error_msg(msg_num, incoming_mail))
self.log_error("Unable to fetch email", self.make_error_msg(msg_num, incoming_mail))
self.errors = True
frappe.db.rollback()

View file

@ -213,5 +213,5 @@ def has_consumer_access(consumer, update_log):
else:
return frappe.safe_eval(condition, frappe._dict(doc=doc))
except Exception as e:
frappe.log_error(title="has_consumer_access error", message=e)
consumer.log_error("has_consumer_access error")
return False

View file

@ -105,7 +105,7 @@ def enqueue_webhook(doc, webhook):
if i != 2:
continue
else:
raise e
webhook.log_error("Webhook failed")
def log_request(url, headers, data, res):

View file

@ -1362,6 +1362,12 @@ class Document(BaseDocument):
).insert(ignore_permissions=True)
frappe.local.flags.commit = True
def log_error(self, title=None, message=None):
"""Helper function to create an Error Log"""
return frappe.log_error(
message=message, title=title, reference_doctype=self.doctype, reference_name=self.name
)
def get_signature(self):
"""Returns signature (hash) for private URL."""
return hashlib.sha224(get_datetime_str(self.creation).encode()).hexdigest()

View file

@ -6,7 +6,6 @@ from typing import TYPE_CHECKING, Optional, Union
import frappe
from frappe import _
from frappe.database.sequence import get_next_val, set_next_val
from frappe.model import log_types
from frappe.query_builder import DocType
from frappe.utils import cint, cstr, now_datetime
@ -36,6 +35,8 @@ def set_new_name(doc):
doc.name = None
if is_autoincremented(doc.doctype, meta):
from frappe.database.sequence import get_next_val
doc.name = get_next_val(doc.doctype)
return
@ -322,11 +323,14 @@ def get_default_naming_series(doctype):
def validate_name(doctype: str, name: Union[int, str], case: Optional[str] = None):
if not name:
frappe.throw(_("No Name Specified for {0}").format(doctype))
if isinstance(name, int):
if is_autoincremented(doctype):
from frappe.database.sequence import set_next_val
# this will set the sequence val to be the provided name and set it to be used
# so that the sequence will start from the next val of the setted val(name)
set_next_val(doctype, name, is_val_used=True)

View file

@ -254,8 +254,9 @@ def bulk_workflow_approval(docnames, doctype, action):
frappe.db.rollback()
frappe.log_error(
frappe.get_traceback(),
"Workflow {0} threw an error for {1} {2}".format(action, doctype, docname),
title="Workflow {0} threw an error for {1} {2}".format(action, doctype, docname),
reference_doctype="Workflow",
reference_name=action,
)
finally:
if not message_dict:

View file

@ -30,6 +30,7 @@
.my-account-container {
max-width: 800px;
margin: auto;
margin-bottom: 4rem;
}
.account-info {

View file

@ -57,7 +57,7 @@ class EnergyPointRule(Document):
self.apply_only_once,
)
except Exception as e:
frappe.log_error(frappe.get_traceback(), "apply_energy_point")
self.log_error("Energy points failed")
def rule_condition_satisfied(self, doc):
if self.for_doc_event == "New":

View file

@ -92,7 +92,12 @@ def download_multi_pdf(doctype, name, format=None, no_letterhead=False, options=
pdf_options=options,
)
except Exception:
frappe.log_error("Permission Error on doc {} of doctype {}".format(doc_name, doctype_name))
frappe.log_error(
title="Error in Multi PDF download",
message="Permission Error on doc {} of doctype {}".format(doc_name, doctype_name),
reference_doctype=doctype_name,
reference_name=doc_name,
)
frappe.local.response.filename = "{}.pdf".format(name)
frappe.local.response.filecontent = read_multi_pdf(output)

View file

@ -70,6 +70,8 @@ data-web-form="{{ name }}" data-web-form-doctype="{{ doc_type }}" data-login-req
<div class="comments" style="margin-top: 3rem;">
{% include 'templates/includes/comments/comments.html' %}
</div>
{%- else -%}
<div style="height: 3rem"></div>
{%- endif %} {# comments #}
{% endblock page_content %}

View file

@ -20,6 +20,7 @@ def get_response(path=None, http_status_code=200):
except frappe.PermissionError as e:
response = NotPermittedPage(endpoint, http_status_code, exception=e).render()
except Exception as e:
frappe.log_error(f"{path} failed")
response = ErrorPage(exception=e).render()
return response