···
from abc import ABC, abstractmethod
7
-
from contextlib import contextmanager
7
+
from contextlib import ExitStack, contextmanager
from queue import Empty, Queue
9
-
from typing import Any, Dict, Iterator
9
+
from typing import Any, Dict, Iterator, List
from xml.sax.saxutils import XMLGenerator
from xml.sax.xmlreader import AttributesImpl
···
52
-
class Logger(AbstractLogger):
52
+
class CompositeLogger(AbstractLogger):
53
+
def __init__(self, logger_list: List[AbstractLogger]) -> None:
54
+
self.logger_list = logger_list
56
+
def add_logger(self, logger: AbstractLogger) -> None:
57
+
self.logger_list.append(logger)
59
+
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
60
+
for logger in self.logger_list:
61
+
logger.log(message, attributes)
64
+
def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
65
+
with ExitStack() as stack:
66
+
for logger in self.logger_list:
67
+
stack.enter_context(logger.subtest(name, attributes))
71
+
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
72
+
with ExitStack() as stack:
73
+
for logger in self.logger_list:
74
+
stack.enter_context(logger.nested(message, attributes))
77
+
def info(self, *args, **kwargs) -> None: # type: ignore
78
+
for logger in self.logger_list:
79
+
logger.info(*args, **kwargs)
81
+
def warning(self, *args, **kwargs) -> None: # type: ignore
82
+
for logger in self.logger_list:
83
+
logger.warning(*args, **kwargs)
85
+
def error(self, *args, **kwargs) -> None: # type: ignore
86
+
for logger in self.logger_list:
87
+
logger.error(*args, **kwargs)
90
+
def print_serial_logs(self, enable: bool) -> None:
91
+
for logger in self.logger_list:
92
+
logger.print_serial_logs(enable)
94
+
def log_serial(self, message: str, machine: str) -> None:
95
+
for logger in self.logger_list:
96
+
logger.log_serial(message, machine)
99
+
class TerminalLogger(AbstractLogger):
100
+
def __init__(self) -> None:
101
+
self._print_serial_logs = True
103
+
def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str:
104
+
if "machine" in attributes:
105
+
return f"{attributes['machine']}: {message}"
109
+
def _eprint(*args: object, **kwargs: Any) -> None:
110
+
print(*args, file=sys.stderr, **kwargs)
112
+
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
113
+
self._eprint(self.maybe_prefix(message, attributes))
116
+
def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
117
+
with self.nested("subtest: " + name, attributes):
121
+
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
124
+
Style.BRIGHT + Fore.GREEN + message + Style.RESET_ALL, attributes
131
+
self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)")
133
+
def info(self, *args, **kwargs) -> None: # type: ignore
134
+
self.log(*args, **kwargs)
136
+
def warning(self, *args, **kwargs) -> None: # type: ignore
137
+
self.log(*args, **kwargs)
139
+
def error(self, *args, **kwargs) -> None: # type: ignore
140
+
self.log(*args, **kwargs)
142
+
def print_serial_logs(self, enable: bool) -> None:
143
+
self._print_serial_logs = enable
145
+
def log_serial(self, message: str, machine: str) -> None:
146
+
if not self._print_serial_logs:
149
+
self._eprint(Style.DIM + f"{machine} # {message}" + Style.RESET_ALL)
152
+
class XMLLogger(AbstractLogger):
def __init__(self) -> None:
self.logfile = os.environ.get("LOGFILE", "/dev/null")
self.logfile_handle = codecs.open(self.logfile, "wb")
self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8")
self.queue: "Queue[Dict[str, str]]" = Queue()
59
-
self.xml.startDocument()
60
-
self.xml.startElement("logfile", attrs=AttributesImpl({}))
self._print_serial_logs = True
64
-
def print_serial_logs(self, enable: bool) -> None:
65
-
self._print_serial_logs = enable
68
-
def _eprint(*args: object, **kwargs: Any) -> None:
69
-
print(*args, file=sys.stderr, **kwargs)
161
+
self.xml.startDocument()
162
+
self.xml.startElement("logfile", attrs=AttributesImpl({}))
self.xml.endElement("logfile")
···
def error(self, *args, **kwargs) -> None: # type: ignore
self.log(*args, **kwargs)
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
100
-
self._eprint(self.maybe_prefix(message, attributes))
self.log_line(message, attributes)
195
+
def print_serial_logs(self, enable: bool) -> None:
196
+
self._print_serial_logs = enable
def log_serial(self, message: str, machine: str) -> None:
199
+
if not self._print_serial_logs:
self.enqueue({"msg": message, "machine": machine, "type": "serial"})
106
-
if self._print_serial_logs:
107
-
self._eprint(Style.DIM + f"{machine} # {message}" + Style.RESET_ALL)
def enqueue(self, item: Dict[str, str]) -> None:
···
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
131
-
Style.BRIGHT + Fore.GREEN + message + Style.RESET_ALL, attributes
self.xml.startElement("nest", attrs=AttributesImpl({}))
self.xml.startElement("head", attrs=AttributesImpl(attributes))
self.xml.characters(message)
···
self.xml.endElement("nest")
150
-
rootlog: AbstractLogger = Logger()
239
+
terminal_logger = TerminalLogger()
240
+
xml_logger = XMLLogger()
241
+
rootlog: AbstractLogger = CompositeLogger([terminal_logger, xml_logger])