Show More
@@ -18,6 +18,7 b'' | |||||
18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
|
21 | import sys | |||
21 | import logging |
|
22 | import logging | |
22 |
|
23 | |||
23 |
|
24 | |||
@@ -73,16 +74,35 b' class Pyro4AwareFormatter(logging.Format' | |||||
73 |
|
74 | |||
74 | def formatException(self, ei): |
|
75 | def formatException(self, ei): | |
75 | ex_type, ex_value, ex_tb = ei |
|
76 | ex_type, ex_value, ex_tb = ei | |
76 | if hasattr(ex_value, '_pyroTraceback'): |
|
77 | ||
77 | # johbo: Avoiding to import pyro4 until we get an exception |
|
78 | local_tb = logging.Formatter.formatException(self, ei) | |
78 | # which actually has a remote traceback. This avoids issues |
|
79 | if hasattr(ex_value, '_vcs_server_traceback'): | |
79 | # when gunicorn is used with gevent, since the logging would |
|
80 | ||
80 | # trigger an import of Pyro4 before the patches of gevent |
|
81 | def formatRemoteTraceback(remote_tb_lines): | |
81 | # are applied. |
|
82 | result = ["\n +--- This exception occured remotely on VCSServer - Remote traceback:\n\n"] | |
82 | import Pyro4.util |
|
83 | result.append(remote_tb_lines) | |
83 | return ''.join( |
|
84 | result.append("\n +--- End of remote traceback\n") | |
84 | Pyro4.util.getPyroTraceback(ex_type, ex_value, ex_tb)) |
|
85 | return result | |
85 | return logging.Formatter.formatException(self, ei) |
|
86 | ||
|
87 | try: | |||
|
88 | if ex_type is not None and ex_value is None and ex_tb is None: | |||
|
89 | # possible old (3.x) call syntax where caller is only providing exception object | |||
|
90 | if type(ex_type) is not type: | |||
|
91 | raise TypeError( | |||
|
92 | "invalid argument: ex_type should be an exception type, or just supply no arguments at all") | |||
|
93 | if ex_type is None and ex_tb is None: | |||
|
94 | ex_type, ex_value, ex_tb = sys.exc_info() | |||
|
95 | ||||
|
96 | remote_tb = getattr(ex_value, "_vcs_server_traceback", None) | |||
|
97 | ||||
|
98 | if remote_tb: | |||
|
99 | remote_tb = formatRemoteTraceback(remote_tb) | |||
|
100 | return local_tb + ''.join(remote_tb) | |||
|
101 | finally: | |||
|
102 | # clean up cycle to traceback, to allow proper GC | |||
|
103 | del ex_type, ex_value, ex_tb | |||
|
104 | ||||
|
105 | return local_tb | |||
86 |
|
106 | |||
87 |
|
107 | |||
88 | class ColorFormatter(Pyro4AwareFormatter): |
|
108 | class ColorFormatter(Pyro4AwareFormatter): |
@@ -75,7 +75,7 b' def wrap_in_appenlight_if_enabled(app, s' | |||||
75 |
|
75 | |||
76 | class RemoteTracebackTracker(object): |
|
76 | class RemoteTracebackTracker(object): | |
77 | """ |
|
77 | """ | |
78 |
Utility middleware which forwards |
|
78 | Utility middleware which forwards VCSServer remote traceback information. | |
79 | """ |
|
79 | """ | |
80 |
|
80 | |||
81 | def __init__(self, app): |
|
81 | def __init__(self, app): | |
@@ -85,7 +85,7 b' class RemoteTracebackTracker(object):' | |||||
85 | try: |
|
85 | try: | |
86 | return self.application(environ, start_response) |
|
86 | return self.application(environ, start_response) | |
87 | except Exception as e: |
|
87 | except Exception as e: | |
88 |
if hasattr(e, '_ |
|
88 | if hasattr(e, '_vcs_server_traceback'): | |
89 | track_extra_information( |
|
89 | track_extra_information( | |
90 |
environ, 'remote_traceback', |
|
90 | environ, 'remote_traceback', e._vcs_server_traceback) | |
91 | raise |
|
91 | raise |
@@ -218,6 +218,12 b' def _remote_call(url, payload, exception' | |||||
218 | exc._vcs_kind = error['_vcs_kind'] |
|
218 | exc._vcs_kind = error['_vcs_kind'] | |
219 | except KeyError: |
|
219 | except KeyError: | |
220 | pass |
|
220 | pass | |
|
221 | ||||
|
222 | try: | |||
|
223 | exc._vcs_server_traceback = error['traceback'] | |||
|
224 | except KeyError: | |||
|
225 | pass | |||
|
226 | ||||
221 | raise exc |
|
227 | raise exc | |
222 | return response.get('result') |
|
228 | return response.get('result') | |
223 |
|
229 |
@@ -185,10 +185,10 b' def map_vcs_exceptions(func):' | |||||
185 | # The error middleware adds information if it finds |
|
185 | # The error middleware adds information if it finds | |
186 | # __traceback_info__ in a frame object. This way the remote |
|
186 | # __traceback_info__ in a frame object. This way the remote | |
187 | # traceback information is made available in error reports. |
|
187 | # traceback information is made available in error reports. | |
188 |
remote_tb = getattr(e, '_ |
|
188 | remote_tb = getattr(e, '_vcs_server_traceback', None) | |
189 | if remote_tb: |
|
189 | if remote_tb: | |
190 | __traceback_info__ = ( |
|
190 | __traceback_info__ = ( | |
191 |
'Found |
|
191 | 'Found VCSServer remote traceback information:\n\n' + | |
192 | '\n'.join(remote_tb)) |
|
192 | '\n'.join(remote_tb)) | |
193 |
|
193 | |||
194 | # Avoid that remote_tb also appears in the frame |
|
194 | # Avoid that remote_tb also appears in the frame |
@@ -46,6 +46,7 b' function registerRCRoutes() {' | |||||
46 | pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); |
|
46 | pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); | |
47 | pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); |
|
47 | pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); | |
48 | pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); |
|
48 | pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); | |
|
49 | pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); | |||
49 | pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); |
|
50 | pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); | |
50 | pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); |
|
51 | pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); | |
51 | pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
|
52 | pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); |
@@ -1331,22 +1331,21 b' def pytest_runtest_makereport(item, call' | |||||
1331 | """ |
|
1331 | """ | |
1332 | Adding the remote traceback if the exception has this information. |
|
1332 | Adding the remote traceback if the exception has this information. | |
1333 |
|
1333 | |||
1334 |
Pyro4 attaches this information as the attribute `_ |
|
1334 | Pyro4 attaches this information as the attribute `_vcs_server_traceback` | |
1335 | to the exception instance. |
|
1335 | to the exception instance. | |
1336 | """ |
|
1336 | """ | |
1337 | outcome = yield |
|
1337 | outcome = yield | |
1338 | report = outcome.get_result() |
|
1338 | report = outcome.get_result() | |
1339 | if call.excinfo: |
|
1339 | if call.excinfo: | |
1340 |
_add_ |
|
1340 | _add_vcsserver_remote_traceback(report, call.excinfo.value) | |
1341 |
|
1341 | |||
1342 |
|
1342 | |||
1343 |
def _add_ |
|
1343 | def _add_vcsserver_remote_traceback(report, exc): | |
1344 |
|
|
1344 | vcsserver_traceback = getattr(exc, '_vcs_server_traceback', None) | |
1345 |
|
1345 | |||
1346 |
if |
|
1346 | if vcsserver_traceback: | |
1347 | traceback = ''.join(pyro_traceback) |
|
1347 | section = 'VCSServer remote traceback ' + report.when | |
1348 | section = 'Pyro4 remote traceback ' + report.when |
|
1348 | report.sections.append((section, vcsserver_traceback)) | |
1349 | report.sections.append((section, traceback)) |
|
|||
1350 |
|
1349 | |||
1351 |
|
1350 | |||
1352 | @pytest.fixture(scope='session') |
|
1351 | @pytest.fixture(scope='session') |
General Comments 0
You need to be logged in to leave comments.
Login now