--- a/scripts/release/log.py Fri Mar 13 23:12:40 2009 +0000
+++ b/scripts/release/log.py Fri Mar 13 23:12:43 2009 +0000
@@ -26,10 +26,31 @@
]
import logging
+import sys
import util
+# A logging level that is even lower than DEBUG. We use this level to
+# log to file only, when we need to replay something output by
+# bypassing the logging system.
+_TERMINAL_ECHO = 5
+
+
+# Pull in the functions from the logging module, for ease of use
+debug = logging.debug
+info = logging.info
+error = logging.error
+raw = debug # Used for logging raw output like subprocess stdout data.
+
+
+# Save the actual out/err streams before init() replaces them. Users
+# of the logging system can use these files if they need to bypass the
+# logging system for some reason.
+stdout = sys.stdout
+stderr = sys.stderr
+
+
class _ColorizingFormatter(logging.Formatter):
"""A logging formatter that colorizes based on log levels."""
@@ -51,6 +72,35 @@
return util.decolorize(logging.Formatter.format(self, record))
+class FileLikeLogger(object):
+ """A file-like object that logs anything written to it."""
+
+ def __init__(self):
+ self._buffer = []
+
+ def _getBuffer(self):
+ data, self._buffer = ''.join(self._buffer), []
+ return data
+
+ def close(self):
+ self.flush()
+
+ def flush(self):
+ raw(self._getBuffer())
+
+ def write(self, str):
+ lines = str.split('\n')
+ self.writelines(lines[0:-1])
+ self._buffer.append(lines[-1])
+
+ def writelines(self, lines):
+ if not lines:
+ return
+ lines[0] = self._getBuffer() + lines[0]
+ for line in lines:
+ raw(line)
+
+
def init(logfile=None):
"""Initialize the logging subsystem.
@@ -59,7 +109,7 @@
"""
root = logging.getLogger('')
- root.setLevel(logging.DEBUG)
+ root.setLevel(_TERMINAL_ECHO)
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
@@ -68,11 +118,27 @@
if logfile:
transcript = logging.FileHandler(logfile, 'w')
- transcript.setLevel(logging.DEBUG)
+ transcript.setLevel(_TERMINAL_ECHO)
transcript.setFormatter(_DecolorizingFormatter())
root.addHandler(transcript)
+ # Redirect sys.stdout and sys.stderr to logging streams. This will
+ # force everything that is output in this process, even through
+ # 'print', to go to both the console and the transcript (if active).
+ sys.stdout = FileLikeLogger()
+ sys.stderr = FileLikeLogger()
-debug = logging.debug
-info = logging.info
-error = logging.error
+
+def terminal_echo(text, *args, **kwargs):
+ """Echo a message written manually to the terminal.
+
+ This function should be used when you want to echo into the logging
+ system something that you manually wrote to the real
+ stdout/stderr.
+
+ For example, when asking the user for input, you would output the
+ raw prompt to the terminal manually, read the user's response, and
+ then echo both the prompt and the answer back into the logging
+ system for recording.
+ """
+ logging.log(_TERMINAL_ECHO, text, *args, **kwargs)