-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror_manager.py
More file actions
135 lines (112 loc) · 4.98 KB
/
Copy patherror_manager.py
File metadata and controls
135 lines (112 loc) · 4.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import collections
import dataclasses
import datetime
import enum
import functools
import io
import os
import sys
import traceback
from typing import Tuple, List, Optional, Callable
class ErrorLevel(enum.Enum):
CRITICAL = 1
ERROR = 2
WARNING = 4
INFO = 8
TRACE = 16
@dataclasses.dataclass
class ErrorInstance:
error_id: int
datetime_utc: datetime.datetime
error_level: ErrorLevel
direct_causes: Tuple[int, ...]
message: str
stack_trace: List[traceback.FrameSummary]
kwargs: Optional[dict]
def __str__(self):
stack_trace = [f'<file {st.filename}, line {st.lineno} in {st.name}>' for st in self.stack_trace]
return ' '.join((
f'[{self.error_id}]',
str(self.datetime_utc.isoformat()),
f'<{self.error_level}>',
str(self.direct_causes),
repr(self.message),
repr(self.kwargs),
repr(stack_trace),
))
class ErrorManager:
def __init__(self, name, logpath: Optional[os.PathLike] = None):
self.name = name
self.errors: List[ErrorInstance] = []
self.logfile: Optional[io.TextIOWrapper] = None
if logpath is not None:
self.set_logpath(logpath)
self.level_statistics: collections.Counter = collections.Counter()
def set_logpath(self, logpath: os.PathLike):
if self.logfile is not None:
self.logfile.close()
self.logpath = logpath
self.logfile = open(self.logpath, 'w', encoding='utf_8')
def check_is_ready(self):
if not hasattr(self, 'logpath'):
raise Exception('ERROR: ErrorManager: `self.logpath` not set. abort.')
if getattr(self, 'logfile') is None:
raise Exception('ERROR: ErrorManager: `self.logfile` is None. abort.')
def is_critical_happened(self) -> bool:
return self.level_statistics[ErrorLevel.CRITICAL] > 0
def is_error_happened(self) -> bool:
return self.level_statistics[ErrorLevel.ERROR] > 0
def is_error_or_worse_happened(self) -> bool:
return self.is_error_happened() or self.is_critical_happened()
def add_message(
self, error_level: ErrorLevel, message: str, direct_causes: Tuple[int, ...] = (), /, *,
ignore_traces: int = 1, **kwargs):
self.check_is_ready()
datetime_utc = datetime.datetime.utcnow()
stack_trace = traceback.extract_stack()[:-ignore_traces]
error_id = len(self.errors)
error = ErrorInstance(error_id, datetime_utc, error_level, direct_causes, message, stack_trace, kwargs)
self.errors.append(error)
self.level_statistics[error_level] += 1
if self.logfile is not None:
self.logfile.write(str(error) + '\n')
return error_id
def add_critical(self, message: str, direct_causes: Tuple[int, ...] = (), **kwargs):
self.add_message(ErrorLevel.CRITICAL, message, direct_causes, ignore_traces=2, **kwargs)
raise Exception(message)
def add_error(self, message: str, direct_causes: Tuple[int, ...] = (), **kwargs):
return self.add_message(ErrorLevel.ERROR, message, direct_causes, ignore_traces=2, **kwargs)
def add_warning(self, message: str, direct_causes: Tuple[int, ...] = (), **kwargs):
return self.add_message(ErrorLevel.WARNING, message, direct_causes, ignore_traces=2, **kwargs)
def add_info(self, message: str, direct_causes: Tuple[int, ...] = (), **kwargs):
return self.add_message(ErrorLevel.INFO, message, direct_causes, ignore_traces=2, **kwargs)
def add_trace(self, message: str, direct_causes: Tuple[int, ...] = (), **kwargs):
return self.add_message(ErrorLevel.TRACE, message, direct_causes, ignore_traces=2, **kwargs)
def add_exception(
self, error_level: ErrorLevel, exc: Exception, **kwargs):
self.check_is_ready()
datetime_utc = datetime.datetime.utcnow()
message = traceback.format_exc().splitlines()[-1]
stack_trace = traceback.extract_tb(sys.exc_info()[2])
error_id = len(self.errors)
error = ErrorInstance(error_id, datetime_utc, error_level, (), message, stack_trace, kwargs)
self.errors.append(error)
self.level_statistics[error_level] += 1
if self.logfile is not None:
self.logfile.write(str(error) + '\n')
return error_id
def add_critical_exception(self, exc: Exception, **kwargs):
self.add_exception(ErrorLevel.CRITICAL, exc, **kwargs)
raise exc
def add_error_exception(self, exc: Exception, **kwargs):
return self.add_exception(ErrorLevel.ERROR, exc, **kwargs)
def trace_func_enter_leave(error_manager: ErrorManager):
def deco_func(func: Callable):
@functools.wraps(func)
def wrapper(*args, **kwargs):
error_manager.add_trace(f'function {func.__name__} started.')
result = func(*args, **kwargs)
error_manager.add_trace(f'function {func.__name__} finished.')
return result
return wrapper
return deco_func