|
1
|
|
|
import traceback |
|
2
|
|
|
from pyprint.ColorPrinter import ColorPrinter |
|
3
|
|
|
|
|
4
|
|
|
from coalib.output.printers.LOG_LEVEL import LOG_LEVEL, LOG_LEVEL_COLORS |
|
5
|
|
|
from coalib.processes.communication.LogMessage import LogMessage |
|
6
|
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
8
|
|
|
class LogPrinter: |
|
9
|
|
|
""" |
|
10
|
|
|
The LogPrinter class allows to print log messages to an underlying Printer. |
|
11
|
|
|
|
|
12
|
|
|
This class is an adapter, means you can create a LogPrinter from every |
|
13
|
|
|
existing Printer instance. |
|
14
|
|
|
""" |
|
15
|
|
|
def __init__(self, |
|
16
|
|
|
printer, |
|
17
|
|
|
log_level=LOG_LEVEL.WARNING, |
|
18
|
|
|
timestamp_format="%X"): |
|
19
|
|
|
""" |
|
20
|
|
|
Creates a new log printer from an existing Printer. |
|
21
|
|
|
|
|
22
|
|
|
:param printer: The underlying Printer where log messages |
|
23
|
|
|
shall be written to. If you inherit from |
|
24
|
|
|
LogPrinter, set it to self. |
|
25
|
|
|
:param log_level: The minimum log level, everything below will |
|
26
|
|
|
not be logged. |
|
27
|
|
|
:param timestamp_format: The format string for the |
|
28
|
|
|
datetime.today().strftime(format) method. |
|
29
|
|
|
""" |
|
30
|
|
|
self._printer = printer |
|
31
|
|
|
self.log_level = log_level |
|
32
|
|
|
self.timestamp_format = timestamp_format |
|
33
|
|
|
|
|
34
|
|
|
@property |
|
35
|
|
|
def printer(self): |
|
36
|
|
|
""" |
|
37
|
|
|
Returns the underlying printer where logs are printed to. |
|
38
|
|
|
""" |
|
39
|
|
|
return self._printer |
|
40
|
|
|
|
|
41
|
|
|
def _get_log_prefix(self, log_level, timestamp): |
|
42
|
|
|
datetime_string = timestamp.strftime(self.timestamp_format) |
|
43
|
|
|
|
|
44
|
|
|
if datetime_string != "": |
|
45
|
|
|
datetime_string = "[" + datetime_string + "]" |
|
46
|
|
|
|
|
47
|
|
|
return '[{}]{}'.format(LOG_LEVEL.reverse.get(log_level, "ERROR"), |
|
48
|
|
|
datetime_string) |
|
49
|
|
|
|
|
50
|
|
|
def debug(self, *messages, delimiter=" ", timestamp=None, **kwargs): |
|
51
|
|
|
self.log_message(LogMessage(LOG_LEVEL.DEBUG, |
|
52
|
|
|
*messages, |
|
53
|
|
|
delimiter=delimiter, |
|
54
|
|
|
timestamp=timestamp), |
|
55
|
|
|
**kwargs) |
|
56
|
|
|
|
|
57
|
|
|
def info(self, *messages, delimiter=" ", timestamp=None, **kwargs): |
|
58
|
|
|
self.log_message(LogMessage(LOG_LEVEL.INFO, |
|
59
|
|
|
*messages, |
|
60
|
|
|
delimiter=delimiter, |
|
61
|
|
|
timestamp=timestamp), |
|
62
|
|
|
**kwargs) |
|
63
|
|
|
|
|
64
|
|
|
def warn(self, *messages, delimiter=" ", timestamp=None, **kwargs): |
|
65
|
|
|
self.log_message(LogMessage(LOG_LEVEL.WARNING, |
|
66
|
|
|
*messages, |
|
67
|
|
|
delimiter=delimiter, |
|
68
|
|
|
timestamp=timestamp), |
|
69
|
|
|
**kwargs) |
|
70
|
|
|
|
|
71
|
|
|
def err(self, *messages, delimiter=" ", timestamp=None, **kwargs): |
|
72
|
|
|
self.log_message(LogMessage(LOG_LEVEL.ERROR, |
|
73
|
|
|
*messages, |
|
74
|
|
|
delimiter=delimiter, |
|
75
|
|
|
timestamp=timestamp), |
|
76
|
|
|
**kwargs) |
|
77
|
|
|
|
|
78
|
|
|
def log(self, log_level, message, timestamp=None, **kwargs): |
|
79
|
|
|
self.log_message(LogMessage(log_level, |
|
80
|
|
|
message, |
|
81
|
|
|
timestamp=timestamp), |
|
82
|
|
|
**kwargs) |
|
83
|
|
|
|
|
84
|
|
|
def log_exception(self, |
|
85
|
|
|
message, |
|
86
|
|
|
exception, |
|
87
|
|
|
log_level=LOG_LEVEL.ERROR, |
|
88
|
|
|
timestamp=None, |
|
89
|
|
|
**kwargs): |
|
90
|
|
|
""" |
|
91
|
|
|
If the log_level of the printer is greater than DEBUG, it prints |
|
92
|
|
|
only the message. If it is DEBUG or lower, it shows the message |
|
93
|
|
|
along with the traceback of the exception. |
|
94
|
|
|
|
|
95
|
|
|
:param message: The message to print. |
|
96
|
|
|
:param exception: The exception to print. |
|
97
|
|
|
:param log_level: The log_level of this message (not used when |
|
98
|
|
|
logging the traceback. Tracebacks always have |
|
99
|
|
|
a level of DEBUG). |
|
100
|
|
|
:param timestamp: The time at which this log occured. Defaults to |
|
101
|
|
|
the current time. |
|
102
|
|
|
:param kwargs: Keyword arguments to be passed when logging the |
|
103
|
|
|
message (not used when logging the traceback). |
|
104
|
|
|
""" |
|
105
|
|
|
if not isinstance(exception, BaseException): |
|
106
|
|
|
raise TypeError("log_exception can only log derivatives of " |
|
107
|
|
|
"BaseException.") |
|
108
|
|
|
|
|
109
|
|
|
traceback_str = "\n".join( |
|
110
|
|
|
traceback.format_exception(type(exception), |
|
111
|
|
|
exception, |
|
112
|
|
|
exception.__traceback__)) |
|
113
|
|
|
|
|
114
|
|
|
self.log(log_level, message, timestamp=timestamp, **kwargs) |
|
115
|
|
|
self.log_message( |
|
116
|
|
|
LogMessage(LOG_LEVEL.DEBUG, |
|
117
|
|
|
"Exception was:" + "\n" + traceback_str, |
|
118
|
|
|
timestamp=timestamp), |
|
119
|
|
|
**kwargs) |
|
120
|
|
|
|
|
121
|
|
|
def log_message(self, log_message, **kwargs): |
|
122
|
|
|
if not isinstance(log_message, LogMessage): |
|
123
|
|
|
raise TypeError("log_message should be of type LogMessage.") |
|
124
|
|
|
|
|
125
|
|
|
if log_message.log_level < self.log_level: |
|
126
|
|
|
return |
|
127
|
|
|
|
|
128
|
|
|
self._print_log_message( |
|
129
|
|
|
self._get_log_prefix(log_message.log_level, log_message.timestamp), |
|
130
|
|
|
log_message, |
|
131
|
|
|
**kwargs) |
|
132
|
|
|
|
|
133
|
|
|
def _print_log_message(self, prefix, log_message, **kwargs): |
|
134
|
|
|
""" |
|
135
|
|
|
Override this if you want to influence how the log message is printed. |
|
136
|
|
|
|
|
137
|
|
|
If the underlying printer is a ColorPrinter, then colored logging is |
|
138
|
|
|
used. You can turn it off in the underlying ColorPrinter if you want to |
|
139
|
|
|
print uncolored. |
|
140
|
|
|
|
|
141
|
|
|
:param prefix: The prefix to print (as string). |
|
142
|
|
|
:param log_message: The LogMessage object to print. |
|
143
|
|
|
:param kwargs: Any other keyword arguments. |
|
144
|
|
|
""" |
|
145
|
|
|
if isinstance(self._printer, ColorPrinter): |
|
146
|
|
|
self.printer.print(prefix, |
|
147
|
|
|
end=" ", |
|
148
|
|
|
color=LOG_LEVEL_COLORS[log_message.log_level], |
|
149
|
|
|
**kwargs) |
|
150
|
|
|
self.printer.print(log_message.message, **kwargs) |
|
151
|
|
|
else: |
|
152
|
|
|
self.printer.print(prefix, log_message.message, **kwargs) |
|
153
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.