Show More
@@ -0,0 +1,18 b'' | |||||
|
1 | ## -*- coding: utf-8 -*- | |||
|
2 | <%inherit file="base.mako"/> | |||
|
3 | <%namespace name="base" file="base.mako"/> | |||
|
4 | ||||
|
5 | <%def name="subject()" filter="n,trim,whitespace_filter"> | |||
|
6 | ${email_prefix} ${exc_type_name} (${exc_id}) | |||
|
7 | </%def> | |||
|
8 | ||||
|
9 | ## plain text version of the email. Empty by default | |||
|
10 | <%def name="body_plaintext()" filter="n,trim"> | |||
|
11 | NO PLAINTEXT VERSION | |||
|
12 | </%def> | |||
|
13 | ||||
|
14 | <h4>${_('Exception `{}` generated on UTC date: {}').format(exc_traceback.get('exc_type', 'NO_TYPE'), exc_traceback.get('exc_utc_date', 'NO_DATE'))}</h4> | |||
|
15 | <p> | |||
|
16 | View exception <a href="${exc_url}">${exc_id}</a> | |||
|
17 | </p> | |||
|
18 | <pre>${exc_traceback.get('exc_message', 'NO_MESSAGE')}</pre> |
@@ -350,6 +350,17 b' labs_settings_active = true' | |||||
350 | ; This is used to store exception from RhodeCode in shared directory |
|
350 | ; This is used to store exception from RhodeCode in shared directory | |
351 | #exception_tracker.store_path = |
|
351 | #exception_tracker.store_path = | |
352 |
|
352 | |||
|
353 | ; Send email with exception details when it happens | |||
|
354 | #exception_tracker.send_email = false | |||
|
355 | ||||
|
356 | ; Comma separated list of recipients for exception emails, | |||
|
357 | ; e.g admin@rhodecode.com,devops@rhodecode.com | |||
|
358 | ; Can be left empty, then emails will be sent to ALL super-admins | |||
|
359 | #exception_tracker.send_email_recipients = | |||
|
360 | ||||
|
361 | ; optional prefix to Add to email Subject | |||
|
362 | #exception_tracker.email_prefix = [RHODECODE ERROR] | |||
|
363 | ||||
353 | ; File store configuration. This is used to store and serve uploaded files |
|
364 | ; File store configuration. This is used to store and serve uploaded files | |
354 | file_store.enabled = true |
|
365 | file_store.enabled = true | |
355 |
|
366 |
@@ -301,6 +301,17 b' labs_settings_active = true' | |||||
301 | ; This is used to store exception from RhodeCode in shared directory |
|
301 | ; This is used to store exception from RhodeCode in shared directory | |
302 | #exception_tracker.store_path = |
|
302 | #exception_tracker.store_path = | |
303 |
|
303 | |||
|
304 | ; Send email with exception details when it happens | |||
|
305 | #exception_tracker.send_email = false | |||
|
306 | ||||
|
307 | ; Comma separated list of recipients for exception emails, | |||
|
308 | ; e.g admin@rhodecode.com,devops@rhodecode.com | |||
|
309 | ; Can be left empty, then emails will be sent to ALL super-admins | |||
|
310 | #exception_tracker.send_email_recipients = | |||
|
311 | ||||
|
312 | ; optional prefix to Add to email Subject | |||
|
313 | #exception_tracker.email_prefix = [RHODECODE ERROR] | |||
|
314 | ||||
304 | ; File store configuration. This is used to store and serve uploaded files |
|
315 | ; File store configuration. This is used to store and serve uploaded files | |
305 | file_store.enabled = true |
|
316 | file_store.enabled = true | |
306 |
|
317 |
@@ -88,6 +88,15 b' Check if we should use full-topic or min' | |||||
88 | 'modified': ['b/modified_file.rst'], |
|
88 | 'modified': ['b/modified_file.rst'], | |
89 | 'removed': ['.idea'], |
|
89 | 'removed': ['.idea'], | |
90 | }) |
|
90 | }) | |
|
91 | ||||
|
92 | exc_traceback = { | |||
|
93 | 'exc_utc_date': '2020-03-26T12:54:50.683281', | |||
|
94 | 'exc_id': 139638856342656, | |||
|
95 | 'exc_timestamp': '1585227290.683288', | |||
|
96 | 'version': 'v1', | |||
|
97 | 'exc_message': 'Traceback (most recent call last):\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/tweens.py", line 41, in excview_tween\n response = handler(request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/router.py", line 148, in handle_request\n registry, request, context, context_iface, view_name\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/view.py", line 667, in _call_view\n response = view_callable(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/config/views.py", line 188, in attr_view\n return view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/config/views.py", line 214, in predicate_wrapper\n return view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/viewderivers.py", line 401, in viewresult_to_response\n result = view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/viewderivers.py", line 132, in _class_view\n response = getattr(inst, attr)()\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/apps/debug_style/views.py", line 355, in render_email\n template_type, **email_kwargs.get(email_id, {}))\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/model/notification.py", line 402, in render_email\n body = email_template.render(None, **_kwargs)\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/lib/partial_renderer.py", line 95, in render\n return self._render_with_exc(tmpl, args, kwargs)\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/lib/partial_renderer.py", line 79, in _render_with_exc\n return render_func.render(*args, **kwargs)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/template.py", line 476, in render\n return runtime._render(self, self.callable_, args, data)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 883, in _render\n **_kwargs_for_callable(callable_, data)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 920, in _render_context\n _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 947, in _exec_template\n callable_(context, *args, **kwargs)\n File "rhodecode_templates_email_templates_base_mako", line 63, in render_body\n File "rhodecode_templates_email_templates_exception_tracker_mako", line 43, in render_body\nAttributeError: \'str\' object has no attribute \'get\'\n', | |||
|
98 | 'exc_type': 'AttributeError' | |||
|
99 | } | |||
91 | email_kwargs = { |
|
100 | email_kwargs = { | |
92 | 'test': {}, |
|
101 | 'test': {}, | |
93 | 'message': { |
|
102 | 'message': { | |
@@ -97,6 +106,13 b' Check if we should use full-topic or min' | |||||
97 | 'user': user, |
|
106 | 'user': user, | |
98 | 'date': datetime.datetime.now(), |
|
107 | 'date': datetime.datetime.now(), | |
99 | }, |
|
108 | }, | |
|
109 | 'exception': { | |||
|
110 | 'email_prefix': '[RHODECODE ERROR]', | |||
|
111 | 'exc_id': exc_traceback['exc_id'], | |||
|
112 | 'exc_url': 'http://server-url/{}'.format(exc_traceback['exc_id']), | |||
|
113 | 'exc_type_name': 'NameError', | |||
|
114 | 'exc_traceback': exc_traceback, | |||
|
115 | }, | |||
100 | 'password_reset': { |
|
116 | 'password_reset': { | |
101 | 'password_reset_url': 'http://example.com/reset-rhodecode-password/token', |
|
117 | 'password_reset_url': 'http://example.com/reset-rhodecode-password/token', | |
102 |
|
118 |
@@ -611,6 +611,14 b' def _sanitize_cache_settings(settings):' | |||||
611 | settings, |
|
611 | settings, | |
612 | 'exception_tracker.store_path', |
|
612 | 'exception_tracker.store_path', | |
613 | temp_store, lower=False, default_when_empty=True) |
|
613 | temp_store, lower=False, default_when_empty=True) | |
|
614 | _bool_setting( | |||
|
615 | settings, | |||
|
616 | 'exception_tracker.send_email', | |||
|
617 | 'false') | |||
|
618 | _string_setting( | |||
|
619 | settings, | |||
|
620 | 'exception_tracker.email_prefix', | |||
|
621 | '[RHODECODE ERROR]', lower=False, default_when_empty=True) | |||
614 |
|
622 | |||
615 | # cache_perms |
|
623 | # cache_perms | |
616 | _string_setting( |
|
624 | _string_setting( |
@@ -27,7 +27,6 b' import traceback' | |||||
27 | import tempfile |
|
27 | import tempfile | |
28 | import glob |
|
28 | import glob | |
29 |
|
29 | |||
30 |
|
||||
31 | log = logging.getLogger(__name__) |
|
30 | log = logging.getLogger(__name__) | |
32 |
|
31 | |||
33 | # NOTE: Any changes should be synced with exc_tracking at vcsserver.lib.exc_tracking |
|
32 | # NOTE: Any changes should be synced with exc_tracking at vcsserver.lib.exc_tracking | |
@@ -77,10 +76,11 b' def get_exc_store():' | |||||
77 | return _exc_store_path |
|
76 | return _exc_store_path | |
78 |
|
77 | |||
79 |
|
78 | |||
80 | def _store_exception(exc_id, exc_type_name, exc_traceback, prefix): |
|
79 | def _store_exception(exc_id, exc_type_name, exc_traceback, prefix, send_email=None): | |
81 | """ |
|
80 | """ | |
82 | Low level function to store exception in the exception tracker |
|
81 | Low level function to store exception in the exception tracker | |
83 | """ |
|
82 | """ | |
|
83 | import rhodecode as app | |||
84 |
|
84 | |||
85 | exc_store_path = get_exc_store() |
|
85 | exc_store_path = get_exc_store() | |
86 | exc_data, org_data = exc_serialize(exc_id, exc_traceback, exc_type_name) |
|
86 | exc_data, org_data = exc_serialize(exc_id, exc_traceback, exc_type_name) | |
@@ -92,6 +92,50 b' def _store_exception(exc_id, exc_type_na' | |||||
92 | f.write(exc_data) |
|
92 | f.write(exc_data) | |
93 | log.debug('Stored generated exception %s as: %s', exc_id, stored_exc_path) |
|
93 | log.debug('Stored generated exception %s as: %s', exc_id, stored_exc_path) | |
94 |
|
94 | |||
|
95 | if send_email is None: | |||
|
96 | # NOTE(marcink): read app config unless we specify explicitly | |||
|
97 | send_email = app.CONFIG.get('exception_tracker.send_email', False) | |||
|
98 | ||||
|
99 | if send_email: | |||
|
100 | try: | |||
|
101 | send_exc_email(exc_id, exc_type_name) | |||
|
102 | except Exception: | |||
|
103 | log.exception('Failed to send exception email') | |||
|
104 | pass | |||
|
105 | ||||
|
106 | ||||
|
107 | def send_exc_email(exc_id, exc_type_name): | |||
|
108 | import rhodecode as app | |||
|
109 | from pyramid.threadlocal import get_current_request | |||
|
110 | from rhodecode.apps._base import TemplateArgs | |||
|
111 | from rhodecode.lib.utils2 import aslist | |||
|
112 | from rhodecode.lib.celerylib import run_task, tasks | |||
|
113 | from rhodecode.lib.base import attach_context_attributes | |||
|
114 | from rhodecode.model.notification import EmailNotificationModel | |||
|
115 | ||||
|
116 | request = get_current_request() | |||
|
117 | ||||
|
118 | recipients = aslist(app.CONFIG.get('exception_tracker.send_email_recipients', '')) | |||
|
119 | log.debug('Sending Email exception to: `%s`', recipients or 'all super admins') | |||
|
120 | ||||
|
121 | # NOTE(marcink): needed for email template rendering | |||
|
122 | attach_context_attributes(TemplateArgs(), request, request.user.user_id) | |||
|
123 | ||||
|
124 | email_kwargs = { | |||
|
125 | 'email_prefix': app.CONFIG.get('exception_tracker.email_prefix', '') or '[RHODECODE ERROR]', | |||
|
126 | 'exc_url': request.route_url('admin_settings_exception_tracker_show', exception_id=exc_id), | |||
|
127 | 'exc_id': exc_id, | |||
|
128 | 'exc_type_name': exc_type_name, | |||
|
129 | 'exc_traceback': read_exception(exc_id, prefix=None), | |||
|
130 | } | |||
|
131 | ||||
|
132 | (subject, headers, email_body, | |||
|
133 | email_body_plaintext) = EmailNotificationModel().render_email( | |||
|
134 | EmailNotificationModel.TYPE_EMAIL_EXCEPTION, **email_kwargs) | |||
|
135 | ||||
|
136 | run_task(tasks.send_email, recipients, subject, | |||
|
137 | email_body_plaintext, email_body) | |||
|
138 | ||||
95 |
|
139 | |||
96 | def _prepare_exception(exc_info): |
|
140 | def _prepare_exception(exc_info): | |
97 | exc_type, exc_value, exc_traceback = exc_info |
|
141 | exc_type, exc_value, exc_traceback = exc_info |
@@ -304,6 +304,7 b' class EmailNotificationModel(BaseModel):' | |||||
304 | TYPE_PASSWORD_RESET = 'password_reset' |
|
304 | TYPE_PASSWORD_RESET = 'password_reset' | |
305 | TYPE_PASSWORD_RESET_CONFIRMATION = 'password_reset_confirmation' |
|
305 | TYPE_PASSWORD_RESET_CONFIRMATION = 'password_reset_confirmation' | |
306 | TYPE_EMAIL_TEST = 'email_test' |
|
306 | TYPE_EMAIL_TEST = 'email_test' | |
|
307 | TYPE_EMAIL_EXCEPTION = 'exception' | |||
307 | TYPE_TEST = 'test' |
|
308 | TYPE_TEST = 'test' | |
308 |
|
309 | |||
309 | email_types = { |
|
310 | email_types = { | |
@@ -311,6 +312,8 b' class EmailNotificationModel(BaseModel):' | |||||
311 | 'rhodecode:templates/email_templates/main.mako', |
|
312 | 'rhodecode:templates/email_templates/main.mako', | |
312 | TYPE_TEST: |
|
313 | TYPE_TEST: | |
313 | 'rhodecode:templates/email_templates/test.mako', |
|
314 | 'rhodecode:templates/email_templates/test.mako', | |
|
315 | TYPE_EMAIL_EXCEPTION: | |||
|
316 | 'rhodecode:templates/email_templates/exception_tracker.mako', | |||
314 | TYPE_EMAIL_TEST: |
|
317 | TYPE_EMAIL_TEST: | |
315 | 'rhodecode:templates/email_templates/email_test.mako', |
|
318 | 'rhodecode:templates/email_templates/email_test.mako', | |
316 | TYPE_REGISTRATION: |
|
319 | TYPE_REGISTRATION: |
General Comments 0
You need to be logged in to leave comments.
Login now