1
|
1 |
|
from plugin.core.constants import PLUGIN_VERSION_BASE, PLUGIN_VERSION_BRANCH, PMS_PATH |
2
|
1 |
|
from plugin.core.helpers.error import ErrorHasher |
3
|
1 |
|
from plugin.managers.core.base import Manager, Create |
|
|
|
|
4
|
1 |
|
from plugin.managers.message import MessageManager |
5
|
|
|
from plugin.models.exception import Exception |
|
|
|
|
6
|
1 |
|
|
7
|
1 |
|
from datetime import datetime |
8
|
1 |
|
import logging |
9
|
1 |
|
import os |
10
|
1 |
|
import re |
11
|
1 |
|
import sys |
12
|
1 |
|
|
13
|
|
|
VERSION_BASE = '.'.join([str(x) for x in PLUGIN_VERSION_BASE]) |
14
|
1 |
|
VERSION_BRANCH = PLUGIN_VERSION_BRANCH |
15
|
1 |
|
|
16
|
|
|
RE_TRACEBACK = re.compile(r"\w+ \(most recent call last\)\:\n(?P<traceback>(?:.*?\n)*)(?P<type>\w+)\: (?P<message>.*?)(?:\n|$)", re.IGNORECASE) |
|
|
|
|
17
|
1 |
|
|
18
|
1 |
|
log = logging.getLogger(__name__) |
19
|
|
|
|
20
|
|
|
|
21
|
|
|
class CreateException(Create): |
22
|
1 |
|
# |
23
|
1 |
|
# exc_info |
24
|
1 |
|
# |
25
|
|
|
|
26
|
1 |
|
def from_exc_info(self, exc_info=None): |
27
|
|
|
if exc_info is None: |
28
|
1 |
|
# Retrieve `exc_info` of last exception |
29
|
|
|
exc_info = sys.exc_info() |
30
|
|
|
|
31
|
1 |
|
# Create exception |
32
|
|
|
exception = self.model( |
|
|
|
|
33
|
|
|
type=self.manager.exc_type(exc_info[0]), |
|
|
|
|
34
|
|
|
message=self.manager.exc_message(exc_info[1]), |
|
|
|
|
35
|
|
|
traceback=self.manager.exc_traceback(exc_info[2]), |
|
|
|
|
36
|
1 |
|
|
37
|
|
|
timestamp=datetime.utcnow(), |
38
|
|
|
version_base=VERSION_BASE, |
39
|
|
|
version_branch=VERSION_BRANCH |
40
|
|
|
) |
41
|
|
|
|
42
|
|
|
# Calculate exception hash |
43
|
|
|
exception.hash = ErrorHasher.hash(exception) |
44
|
|
|
|
45
|
|
|
# Create/Lookup message for exception |
46
|
|
|
exception.error = MessageManager.get.from_exception(exception) |
|
|
|
|
47
|
|
|
|
48
|
|
|
# Save exception details |
49
|
|
|
exception.save() |
50
|
|
|
|
51
|
|
|
return exception, exception.error |
52
|
|
|
|
53
|
|
|
# |
54
|
|
|
# message |
55
|
|
|
# |
56
|
|
|
|
57
|
|
|
def from_message(self, message): |
58
|
|
|
match = RE_TRACEBACK.match(message) |
59
|
|
|
|
60
|
|
|
if match is None: |
61
|
|
|
return |
62
|
|
|
|
63
|
|
|
# Create exception |
64
|
|
|
exception = self.model( |
|
|
|
|
65
|
|
|
type=match.group('type'), |
66
|
|
|
message=match.group('message'), |
67
|
1 |
|
traceback=self.strip_traceback(match.group('traceback')), |
68
|
|
|
|
69
|
|
|
timestamp=datetime.utcnow(), |
70
|
|
|
version_base=VERSION_BASE, |
71
|
|
|
version_branch=VERSION_BRANCH |
72
|
|
|
) |
73
|
|
|
|
74
|
|
|
# Calculate exception hash |
75
|
|
|
exception.hash = ErrorHasher.hash(exception) |
76
|
|
|
|
77
|
|
|
# Create/Lookup message for exception |
78
|
|
|
exception.error = MessageManager.get.from_exception(exception) |
|
|
|
|
79
|
|
|
|
80
|
|
|
# Save exception details |
81
|
|
|
exception.save() |
82
|
|
|
|
83
|
|
|
return exception, exception.error |
84
|
|
|
|
85
|
|
|
@staticmethod |
86
|
|
|
def strip_traceback(tb): |
87
|
|
|
lines = tb.split('\n') |
88
|
|
|
|
89
|
|
|
for x in xrange(len(lines)): |
|
|
|
|
90
|
|
|
line = lines[x] |
91
|
|
|
|
92
|
|
|
if not line.startswith(' File'): |
93
|
|
|
continue |
94
|
|
|
|
95
|
1 |
|
try: |
96
|
|
|
# Try find path start/end quotes |
97
|
|
|
path_start = line.index('"') + 1 |
98
|
|
|
path_end = line.index('"', path_start) |
99
|
|
|
except ValueError: |
100
|
|
|
# Unable to find path quotes |
101
|
|
|
continue |
102
|
|
|
|
103
|
|
|
# Convert path to relative |
104
|
|
|
path = os.path.relpath(line[path_start:path_end], PMS_PATH) |
105
|
|
|
|
106
|
|
|
# Update line |
107
|
|
|
lines[x] = line[:path_start] + path + line[path_end:] |
108
|
|
|
|
109
|
|
|
return '\n'.join(lines) |
110
|
|
|
|
111
|
|
|
|
112
|
|
|
class ExceptionManager(Manager): |
|
|
|
|
113
|
|
|
create = CreateException |
114
|
|
|
|
115
|
|
|
model = Exception |
116
|
|
|
|