Unreviewed. Update W3C WebDriver imported tests.
[WebKit-https.git] / WebDriverTests / imported / w3c / tools / wptrunner / wptrunner / wptlogging.py
1 import logging
2 import sys
3 import threading
4 from StringIO import StringIO
5 from multiprocessing import Queue
6
7 from mozlog import commandline, stdadapter
8
9 def setup(args, defaults):
10     logger = commandline.setup_logging("web-platform-tests", args, defaults)
11     setup_stdlib_logger()
12
13     for name in args.keys():
14         if name.startswith("log_"):
15             args.pop(name)
16
17     return logger
18
19
20 def setup_stdlib_logger():
21     logging.root.handlers = []
22     logging.root = stdadapter.std_logging_adapter(logging.root)
23
24
25 class LogLevelRewriter(object):
26     """Filter that replaces log messages at specified levels with messages
27     at a different level.
28
29     This can be used to e.g. downgrade log messages from ERROR to WARNING
30     in some component where ERRORs are not critical.
31
32     :param inner: Handler to use for messages that pass this filter
33     :param from_levels: List of levels which should be affected
34     :param to_level: Log level to set for the affected messages
35     """
36     def __init__(self, inner, from_levels, to_level):
37         self.inner = inner
38         self.from_levels = [item.upper() for item in from_levels]
39         self.to_level = to_level.upper()
40
41     def __call__(self, data):
42         if data["action"] == "log" and data["level"].upper() in self.from_levels:
43             data = data.copy()
44             data["level"] = self.to_level
45         return self.inner(data)
46
47
48
49 class LogThread(threading.Thread):
50     def __init__(self, queue, logger, level):
51         self.queue = queue
52         self.log_func = getattr(logger, level)
53         threading.Thread.__init__(self, name="Thread-Log")
54         self.daemon = True
55
56     def run(self):
57         while True:
58             try:
59                 msg = self.queue.get()
60             except (EOFError, IOError):
61                 break
62             if msg is None:
63                 break
64             else:
65                 self.log_func(msg)
66
67
68 class LoggingWrapper(StringIO):
69     """Wrapper for file like objects to redirect output to logger
70     instead"""
71
72     def __init__(self, queue, prefix=None):
73         StringIO.__init__(self)
74         self.queue = queue
75         self.prefix = prefix
76
77     def write(self, data):
78         if isinstance(data, str):
79             try:
80                 data = data.decode("utf8")
81             except UnicodeDecodeError:
82                 data = data.encode("string_escape").decode("ascii")
83
84         if data.endswith("\n"):
85             data = data[:-1]
86         if data.endswith("\r"):
87             data = data[:-1]
88         if not data:
89             return
90         if self.prefix is not None:
91             data = "%s: %s" % (self.prefix, data)
92         self.queue.put(data)
93
94     def flush(self):
95         pass
96
97
98 class CaptureIO(object):
99     def __init__(self, logger, do_capture):
100         self.logger = logger
101         self.do_capture = do_capture
102         self.logging_queue = None
103         self.logging_thread = None
104         self.original_stdio = None
105
106     def __enter__(self):
107         if self.do_capture:
108             self.original_stdio = (sys.stdout, sys.stderr)
109             self.logging_queue = Queue()
110             self.logging_thread = LogThread(self.logging_queue, self.logger, "info")
111             sys.stdout = LoggingWrapper(self.logging_queue, prefix="STDOUT")
112             sys.stderr = LoggingWrapper(self.logging_queue, prefix="STDERR")
113             self.logging_thread.start()
114
115     def __exit__(self, *args, **kwargs):
116         if self.do_capture:
117             sys.stdout, sys.stderr = self.original_stdio
118             if self.logging_queue is not None:
119                 self.logger.info("Closing logging queue")
120                 self.logging_queue.put(None)
121                 if self.logging_thread is not None:
122                     self.logging_thread.join(10)
123                 self.logging_queue.close()
124                 self.logger.info("queue closed")