##// END OF EJS Templates
exception-tracker: add show-more link.
ergo -
r2985:0dd49fc6 default
parent child Browse files
Show More
@@ -1,153 +1,154 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2018-2018 RhodeCode GmbH
3 # Copyright (C) 2018-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
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 import os
20 import os
21 import logging
21 import logging
22
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 from rhodecode.apps._base import BaseAppView
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps.admin.navigation import navigation_list
27 from rhodecode.apps.admin.navigation import navigation_list
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
30 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
31 from rhodecode.lib.utils2 import time_to_utcdatetime
31 from rhodecode.lib.utils2 import time_to_utcdatetime, safe_int
32 from rhodecode.lib import exc_tracking
32 from rhodecode.lib import exc_tracking
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
36
36
37 class ExceptionsTrackerView(BaseAppView):
37 class ExceptionsTrackerView(BaseAppView):
38 def load_default_context(self):
38 def load_default_context(self):
39 c = self._get_local_tmpl_context()
39 c = self._get_local_tmpl_context()
40 c.navlist = navigation_list(self.request)
40 c.navlist = navigation_list(self.request)
41 return c
41 return c
42
42
43 def count_all_exceptions(self):
43 def count_all_exceptions(self):
44 exc_store_path = exc_tracking.get_exc_store()
44 exc_store_path = exc_tracking.get_exc_store()
45 count = 0
45 count = 0
46 for fname in os.listdir(exc_store_path):
46 for fname in os.listdir(exc_store_path):
47 parts = fname.split('_', 2)
47 parts = fname.split('_', 2)
48 if not len(parts) == 3:
48 if not len(parts) == 3:
49 continue
49 continue
50 count +=1
50 count +=1
51 return count
51 return count
52
52
53 def get_all_exceptions(self, read_metadata=False, limit=None):
53 def get_all_exceptions(self, read_metadata=False, limit=None):
54 exc_store_path = exc_tracking.get_exc_store()
54 exc_store_path = exc_tracking.get_exc_store()
55 exception_list = []
55 exception_list = []
56
56
57 def key_sorter(val):
57 def key_sorter(val):
58 try:
58 try:
59 return val.split('_')[-1]
59 return val.split('_')[-1]
60 except Exception:
60 except Exception:
61 return 0
61 return 0
62 count = 0
62 count = 0
63 for fname in reversed(sorted(os.listdir(exc_store_path), key=key_sorter)):
63 for fname in reversed(sorted(os.listdir(exc_store_path), key=key_sorter)):
64
64
65 parts = fname.split('_', 2)
65 parts = fname.split('_', 2)
66 if not len(parts) == 3:
66 if not len(parts) == 3:
67 continue
67 continue
68
68
69 exc_id, app_type, exc_timestamp = parts
69 exc_id, app_type, exc_timestamp = parts
70
70
71 exc = {'exc_id': exc_id, 'app_type': app_type, 'exc_type': 'unknown',
71 exc = {'exc_id': exc_id, 'app_type': app_type, 'exc_type': 'unknown',
72 'exc_utc_date': '', 'exc_timestamp': exc_timestamp}
72 'exc_utc_date': '', 'exc_timestamp': exc_timestamp}
73
73
74 if read_metadata:
74 if read_metadata:
75 full_path = os.path.join(exc_store_path, fname)
75 full_path = os.path.join(exc_store_path, fname)
76 # we can read our metadata
76 # we can read our metadata
77 with open(full_path, 'rb') as f:
77 with open(full_path, 'rb') as f:
78 exc_metadata = exc_tracking.exc_unserialize(f.read())
78 exc_metadata = exc_tracking.exc_unserialize(f.read())
79 exc.update(exc_metadata)
79 exc.update(exc_metadata)
80
80
81 # convert our timestamp to a date obj, for nicer representation
81 # convert our timestamp to a date obj, for nicer representation
82 exc['exc_utc_date'] = time_to_utcdatetime(exc['exc_timestamp'])
82 exc['exc_utc_date'] = time_to_utcdatetime(exc['exc_timestamp'])
83 exception_list.append(exc)
83 exception_list.append(exc)
84
84
85 count += 1
85 count += 1
86 if limit and count >= limit:
86 if limit and count >= limit:
87 break
87 break
88 return exception_list
88 return exception_list
89
89
90 @LoginRequired()
90 @LoginRequired()
91 @HasPermissionAllDecorator('hg.admin')
91 @HasPermissionAllDecorator('hg.admin')
92 @view_config(
92 @view_config(
93 route_name='admin_settings_exception_tracker', request_method='GET',
93 route_name='admin_settings_exception_tracker', request_method='GET',
94 renderer='rhodecode:templates/admin/settings/settings.mako')
94 renderer='rhodecode:templates/admin/settings/settings.mako')
95 def browse_exceptions(self):
95 def browse_exceptions(self):
96 _ = self.request.translate
96 _ = self.request.translate
97 c = self.load_default_context()
97 c = self.load_default_context()
98 c.active = 'exceptions_browse'
98 c.active = 'exceptions_browse'
99 c.limit = self.request.GET.get('limit', 50)
99 c.limit = safe_int(self.request.GET.get('limit')) or 50
100 c.next_limit = c.limit + 50
100 c.exception_list = self.get_all_exceptions(read_metadata=True, limit=c.limit)
101 c.exception_list = self.get_all_exceptions(read_metadata=True, limit=c.limit)
101 c.exception_list_count = self.count_all_exceptions()
102 c.exception_list_count = self.count_all_exceptions()
102 c.exception_store_dir = exc_tracking.get_exc_store()
103 c.exception_store_dir = exc_tracking.get_exc_store()
103 return self._get_template_context(c)
104 return self._get_template_context(c)
104
105
105 @LoginRequired()
106 @LoginRequired()
106 @HasPermissionAllDecorator('hg.admin')
107 @HasPermissionAllDecorator('hg.admin')
107 @view_config(
108 @view_config(
108 route_name='admin_settings_exception_tracker_show', request_method='GET',
109 route_name='admin_settings_exception_tracker_show', request_method='GET',
109 renderer='rhodecode:templates/admin/settings/settings.mako')
110 renderer='rhodecode:templates/admin/settings/settings.mako')
110 def exception_show(self):
111 def exception_show(self):
111 _ = self.request.translate
112 _ = self.request.translate
112 c = self.load_default_context()
113 c = self.load_default_context()
113
114
114 c.active = 'exceptions'
115 c.active = 'exceptions'
115 c.exception_id = self.request.matchdict['exception_id']
116 c.exception_id = self.request.matchdict['exception_id']
116 c.traceback = exc_tracking.read_exception(c.exception_id, prefix=None)
117 c.traceback = exc_tracking.read_exception(c.exception_id, prefix=None)
117 return self._get_template_context(c)
118 return self._get_template_context(c)
118
119
119 @LoginRequired()
120 @LoginRequired()
120 @HasPermissionAllDecorator('hg.admin')
121 @HasPermissionAllDecorator('hg.admin')
121 @CSRFRequired()
122 @CSRFRequired()
122 @view_config(
123 @view_config(
123 route_name='admin_settings_exception_tracker_delete_all', request_method='POST',
124 route_name='admin_settings_exception_tracker_delete_all', request_method='POST',
124 renderer='rhodecode:templates/admin/settings/settings.mako')
125 renderer='rhodecode:templates/admin/settings/settings.mako')
125 def exception_delete_all(self):
126 def exception_delete_all(self):
126 _ = self.request.translate
127 _ = self.request.translate
127 c = self.load_default_context()
128 c = self.load_default_context()
128
129
129 c.active = 'exceptions'
130 c.active = 'exceptions'
130 all_exc = self.get_all_exceptions()
131 all_exc = self.get_all_exceptions()
131 exc_count = len(all_exc)
132 exc_count = len(all_exc)
132 for exc in all_exc:
133 for exc in all_exc:
133 exc_tracking.delete_exception(exc['exc_id'], prefix=None)
134 exc_tracking.delete_exception(exc['exc_id'], prefix=None)
134
135
135 h.flash(_('Removed {} Exceptions').format(exc_count), category='success')
136 h.flash(_('Removed {} Exceptions').format(exc_count), category='success')
136 raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
137 raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
137
138
138 @LoginRequired()
139 @LoginRequired()
139 @HasPermissionAllDecorator('hg.admin')
140 @HasPermissionAllDecorator('hg.admin')
140 @CSRFRequired()
141 @CSRFRequired()
141 @view_config(
142 @view_config(
142 route_name='admin_settings_exception_tracker_delete', request_method='POST',
143 route_name='admin_settings_exception_tracker_delete', request_method='POST',
143 renderer='rhodecode:templates/admin/settings/settings.mako')
144 renderer='rhodecode:templates/admin/settings/settings.mako')
144 def exception_delete(self):
145 def exception_delete(self):
145 _ = self.request.translate
146 _ = self.request.translate
146 c = self.load_default_context()
147 c = self.load_default_context()
147
148
148 c.active = 'exceptions'
149 c.active = 'exceptions'
149 c.exception_id = self.request.matchdict['exception_id']
150 c.exception_id = self.request.matchdict['exception_id']
150 exc_tracking.delete_exception(c.exception_id, prefix=None)
151 exc_tracking.delete_exception(c.exception_id, prefix=None)
151
152
152 h.flash(_('Removed Exception {}').format(c.exception_id), category='success')
153 h.flash(_('Removed Exception {}').format(c.exception_id), category='success')
153 raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
154 raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
@@ -1,56 +1,57 b''
1 <div class="panel panel-default">
1 <div class="panel panel-default">
2 <div class="panel-heading">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Exceptions Tracker ')}</h3>
3 <h3 class="panel-title">${_('Exceptions Tracker ')}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 % if c.exception_list_count == 1:
6 % if c.exception_list_count == 1:
7 ${_('There is {} stored exception.').format(c.exception_list_count)}
7 ${_('There is {} stored exception.').format(c.exception_list_count)}
8 % else:
8 % else:
9 ${_('There are {} stored exceptions.').format(c.exception_list_count)}
9 ${_('There are {} stored exceptions.').format(c.exception_list_count)}
10 % endif
10 % endif
11 ${_('Store directory')}: ${c.exception_store_dir}
11 ${_('Store directory')}: ${c.exception_store_dir}
12
12
13 ${h.secure_form(h.route_path('admin_settings_exception_tracker_delete_all'), request=request)}
13 ${h.secure_form(h.route_path('admin_settings_exception_tracker_delete_all'), request=request)}
14 <div style="margin: 0 0 20px 0" class="fake-space"></div>
14 <div style="margin: 0 0 20px 0" class="fake-space"></div>
15
15
16 <div class="field">
16 <div class="field">
17 <button class="btn btn-small btn-danger" type="submit"
17 <button class="btn btn-small btn-danger" type="submit"
18 onclick="return confirm('${_('Confirm to delete all exceptions')}');">
18 onclick="return confirm('${_('Confirm to delete all exceptions')}');">
19 <i class="icon-remove-sign"></i>
19 <i class="icon-remove-sign"></i>
20 ${_('Delete All')}
20 ${_('Delete All')}
21 </button>
21 </button>
22 </div>
22 </div>
23
23
24 ${h.end_form()}
24 ${h.end_form()}
25
25
26 </div>
26 </div>
27 </div>
27 </div>
28
28
29
29
30 <div class="panel panel-default">
30 <div class="panel panel-default">
31 <div class="panel-heading">
31 <div class="panel-heading">
32 <h3 class="panel-title">${_('Exceptions Tracker - Showing the last {} Exceptions').format(c.limit)}</h3>
32 <h3 class="panel-title">${_('Exceptions Tracker - Showing the last {} Exceptions').format(c.limit)}.</h3>
33 <a class="panel-edit" href="${h.current_route_path(request, limit=c.next_limit)}">${_('Show more')}</a>
33 </div>
34 </div>
34 <div class="panel-body">
35 <div class="panel-body">
35 <table class="rctable">
36 <table class="rctable">
36 <tr>
37 <tr>
37 <th>#</th>
38 <th>#</th>
38 <th>Exception ID</th>
39 <th>Exception ID</th>
39 <th>Date</th>
40 <th>Date</th>
40 <th>App Type</th>
41 <th>App Type</th>
41 <th>Exc Type</th>
42 <th>Exc Type</th>
42 </tr>
43 </tr>
43 <% cnt = len(c.exception_list)%>
44 <% cnt = len(c.exception_list)%>
44 % for tb in c.exception_list:
45 % for tb in c.exception_list:
45 <tr>
46 <tr>
46 <td>${cnt}</td>
47 <td>${cnt}</td>
47 <td><a href="${h.route_path('admin_settings_exception_tracker_show', exception_id=tb['exc_id'])}"><code>${tb['exc_id']}</code></a></td>
48 <td><a href="${h.route_path('admin_settings_exception_tracker_show', exception_id=tb['exc_id'])}"><code>${tb['exc_id']}</code></a></td>
48 <td>${h.format_date(tb['exc_utc_date'])}</td>
49 <td>${h.format_date(tb['exc_utc_date'])}</td>
49 <td>${tb['app_type']}</td>
50 <td>${tb['app_type']}</td>
50 <td>${tb['exc_type']}</td>
51 <td>${tb['exc_type']}</td>
51 </tr>
52 </tr>
52 <% cnt -=1 %>
53 <% cnt -=1 %>
53 % endfor
54 % endfor
54 </table>
55 </table>
55 </div>
56 </div>
56 </div>
57 </div>
General Comments 0
You need to be logged in to leave comments. Login now