##// END OF EJS Templates
cache exc store, and use glob.glob for scaning exc store
marcink -
r3975:6411e6b8 default
parent child Browse files
Show More
@@ -1,166 +1,172 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import time
23 23 import datetime
24 24 import msgpack
25 25 import logging
26 26 import traceback
27 27 import tempfile
28 import glob
28 29
29 30
30 31 log = logging.getLogger(__name__)
31 32
32 33 # NOTE: Any changes should be synced with exc_tracking at vcsserver.lib.exc_tracking
33 34 global_prefix = 'rhodecode'
34 35 exc_store_dir_name = 'rc_exception_store_v1'
35 36
36 37
37 38 def exc_serialize(exc_id, tb, exc_type):
38 39
39 40 data = {
40 41 'version': 'v1',
41 42 'exc_id': exc_id,
42 43 'exc_utc_date': datetime.datetime.utcnow().isoformat(),
43 44 'exc_timestamp': repr(time.time()),
44 45 'exc_message': tb,
45 46 'exc_type': exc_type,
46 47 }
47 48 return msgpack.packb(data), data
48 49
49 50
50 51 def exc_unserialize(tb):
51 52 return msgpack.unpackb(tb)
52 53
54 _exc_store = None
55
53 56
54 57 def get_exc_store():
55 58 """
56 59 Get and create exception store if it's not existing
57 60 """
61 global _exc_store
58 62 import rhodecode as app
59 63
64 if _exc_store is not None:
65 # quick global cache
66 return _exc_store
67
60 68 exc_store_dir = app.CONFIG.get('exception_tracker.store_path', '') or tempfile.gettempdir()
61 69 _exc_store_path = os.path.join(exc_store_dir, exc_store_dir_name)
62 70
63 71 _exc_store_path = os.path.abspath(_exc_store_path)
64 72 if not os.path.isdir(_exc_store_path):
65 73 os.makedirs(_exc_store_path)
66 74 log.debug('Initializing exceptions store at %s', _exc_store_path)
75 _exc_store = _exc_store_path
76
67 77 return _exc_store_path
68 78
69 79
70 80 def _store_exception(exc_id, exc_type_name, exc_traceback, prefix):
71 81 """
72 82 Low level function to store exception in the exception tracker
73 83 """
74 84
75 85 exc_store_path = get_exc_store()
76 86 exc_data, org_data = exc_serialize(exc_id, exc_traceback, exc_type_name)
77 87 exc_pref_id = '{}_{}_{}'.format(exc_id, prefix, org_data['exc_timestamp'])
78 88 if not os.path.isdir(exc_store_path):
79 89 os.makedirs(exc_store_path)
80 90 stored_exc_path = os.path.join(exc_store_path, exc_pref_id)
81 91 with open(stored_exc_path, 'wb') as f:
82 92 f.write(exc_data)
83 93 log.debug('Stored generated exception %s as: %s', exc_id, stored_exc_path)
84 94
85 95
86 96 def _prepare_exception(exc_info):
87 97 exc_type, exc_value, exc_traceback = exc_info
88 98 exc_type_name = exc_type.__name__
89 99
90 100 tb = ''.join(traceback.format_exception(
91 101 exc_type, exc_value, exc_traceback, None))
92 102
93 103 return exc_type_name, tb
94 104
95 105
96 106 def store_exception(exc_id, exc_info, prefix=global_prefix):
97 107 """
98 108 Example usage::
99 109
100 110 exc_info = sys.exc_info()
101 111 store_exception(id(exc_info), exc_info)
102 112 """
103 113
104 114 try:
105 115 exc_type_name, exc_traceback = _prepare_exception(exc_info)
106 116 _store_exception(exc_id=exc_id, exc_type_name=exc_type_name,
107 117 exc_traceback=exc_traceback, prefix=prefix)
108 118 except Exception:
109 119 log.exception('Failed to store exception `%s` information', exc_id)
110 120 # there's no way this can fail, it will crash server badly if it does.
111 121 pass
112 122
113 123
114 124 def _find_exc_file(exc_id, prefix=global_prefix):
115 125 exc_store_path = get_exc_store()
116 126 if prefix:
117 127 exc_id = '{}_{}'.format(exc_id, prefix)
118 128 else:
119 129 # search without a prefix
120 130 exc_id = '{}'.format(exc_id)
121 131
122 # we need to search the store for such start pattern as above
123 for fname in os.listdir(exc_store_path):
124 if fname.startswith(exc_id):
125 exc_id = os.path.join(exc_store_path, fname)
126 break
127 continue
128 else:
129 exc_id = None
132 found_exc_id = None
133 matches = glob.glob(os.path.join(exc_store_path, exc_id) + '*')
134 if matches:
135 found_exc_id = matches[0]
130 136
131 return exc_id
137 return found_exc_id
132 138
133 139
134 140 def _read_exception(exc_id, prefix):
135 141 exc_id_file_path = _find_exc_file(exc_id=exc_id, prefix=prefix)
136 142 if exc_id_file_path:
137 143 with open(exc_id_file_path, 'rb') as f:
138 144 return exc_unserialize(f.read())
139 145 else:
140 146 log.debug('Exception File `%s` not found', exc_id_file_path)
141 147 return None
142 148
143 149
144 150 def read_exception(exc_id, prefix=global_prefix):
145 151 try:
146 152 return _read_exception(exc_id=exc_id, prefix=prefix)
147 153 except Exception:
148 154 log.exception('Failed to read exception `%s` information', exc_id)
149 155 # there's no way this can fail, it will crash server badly if it does.
150 156 return None
151 157
152 158
153 159 def delete_exception(exc_id, prefix=global_prefix):
154 160 try:
155 161 exc_id_file_path = _find_exc_file(exc_id, prefix=prefix)
156 162 if exc_id_file_path:
157 163 os.remove(exc_id_file_path)
158 164
159 165 except Exception:
160 166 log.exception('Failed to remove exception `%s` information', exc_id)
161 167 # there's no way this can fail, it will crash server badly if it does.
162 168 pass
163 169
164 170
165 171 def generate_id():
166 172 return id(object())
General Comments 0
You need to be logged in to leave comments. Login now