summaryrefslogtreecommitdiff
path: root/lib/spack/llnl/util/tty/log.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/llnl/util/tty/log.py')
-rw-r--r--lib/spack/llnl/util/tty/log.py67
1 files changed, 53 insertions, 14 deletions
diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py
index 2551a751f4..c16982241e 100644
--- a/lib/spack/llnl/util/tty/log.py
+++ b/lib/spack/llnl/util/tty/log.py
@@ -403,7 +403,52 @@ def replace_environment(env):
os.environ[name] = val
-class log_output(object):
+def log_output(*args, **kwargs):
+ """Context manager that logs its output to a file.
+
+ In the simplest case, the usage looks like this::
+
+ with log_output('logfile.txt'):
+ # do things ... output will be logged
+
+ Any output from the with block will be redirected to ``logfile.txt``.
+ If you also want the output to be echoed to ``stdout``, use the
+ ``echo`` parameter::
+
+ with log_output('logfile.txt', echo=True):
+ # do things ... output will be logged and printed out
+
+ And, if you just want to echo *some* stuff from the parent, use
+ ``force_echo``::
+
+ with log_output('logfile.txt', echo=False) as logger:
+ # do things ... output will be logged
+
+ with logger.force_echo():
+ # things here will be echoed *and* logged
+
+ Under the hood, we spawn a daemon and set up a pipe between this
+ process and the daemon. The daemon writes our output to both the
+ file and to stdout (if echoing). The parent process can communicate
+ with the daemon to tell it when and when not to echo; this is what
+ force_echo does. You can also enable/disable echoing by typing 'v'.
+
+ We try to use OS-level file descriptors to do the redirection, but if
+ stdout or stderr has been set to some Python-level file object, we
+ use Python-level redirection instead. This allows the redirection to
+ work within test frameworks like nose and pytest.
+
+
+ This method is actually a factory serving a per platform
+ (nix vs windows) log_output class
+ """
+ if sys.platform == 'win32':
+ return winlog(*args, **kwargs)
+ else:
+ return nixlog(*args, **kwargs)
+
+
+class nixlog(object):
"""Context manager that logs its output to a file.
In the simplest case, the usage looks like this::
@@ -747,12 +792,13 @@ class StreamWrapper:
os.close(self.saved_stream)
-class winlog:
- def __init__(self, logfile, echo=False, debug=0, env=None):
+class winlog(object):
+ def __init__(self, file_like=None, echo=False, debug=0, buffer=False,
+ env=None, filter_fn=None):
self.env = env
self.debug = debug
self.echo = echo
- self.logfile = logfile
+ self.logfile = file_like
self.stdout = StreamWrapper('stdout')
self.stderr = StreamWrapper('stderr')
self._active = False
@@ -807,6 +853,7 @@ class winlog:
self._thread = Thread(target=background_reader,
args=(self.reader, self.echo_writer, self._kill))
self._thread.start()
+ return self
def __exit__(self, exc_type, exc_val, exc_tb):
if self._ioflag:
@@ -831,18 +878,10 @@ class winlog:
if not self._active:
raise RuntimeError(
"Can't call force_echo() outside log_output region!")
-
- # This uses the xon/xoff to highlight regions to be echoed in the
- # output. We use these control characters rather than, say, a
- # separate pipe, because they're in-band and assured to appear
- # exactly before and after the text we want to echo.
- sys.stdout.write(xon)
- sys.stdout.flush()
try:
- yield
+ yield self
finally:
- sys.stdout.write(xoff)
- sys.stdout.flush()
+ pass
def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo,