There's already a question that answers how to do this regarding sys.stdout
and sys.stderr
here: https://stackoverflow.com/a/14197079/198348
But that doesn't work everywhere. The logging module seems to output to sys.stdout
and sys.stderr
, but I can't capture it with the context manager above.
In the following example code, I'm trying to capture all output inside the context manager, failing to do so for the logger statements:
from __future__ import print_function
import contextlib
import sys
import logging
from StringIO import StringIO# taken from https://stackoverflow.com/a/14197079/198348
@contextlib.contextmanager
def stdout_redirect(where):prev_stdout = sys.stdoutprev_stderr = sys.stderrprev_stdout.flush()sys.stdout = wheresys.stderr = wheretry:yield wherefinally:where.flush()sys.stdout = prev_stdoutsys.stderr = prev_stderrlogging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()print("\t\tOUTSIDE: stdout", file=sys.stdout)
print("\t\tOUTSIDE: stderr", file=sys.stderr)
logger.info("\tOUTSIDE: info")
logger.debug("\tOUTSIDE: debug")
logger.warn("\tOUTSIDE: warn")
logger.error("\tOUTSIDE: error")
logger.critical("\tOUTSIDE: critical")print("=============== DIVIDER ================")s = ""
with stdout_redirect(StringIO()) as new_stdout:print("\t\tINSIDE: stdout", file=sys.stdout)print("\t\tINSIDE: stderr", file=sys.stderr)logger.info("\tINSIDE: info")logger.debug("\tINSIDE: debug")logger.warn("\tINSIDE: warn")logger.error("\tINSIDE: error")logger.critical("\tINSIDE: critical")print("=============== DIVIDER ===============")
print(new_stdout.getvalue())print("=============== LOGGING ===============")print(logger.handlers)
print(logger.root.handlers)
How can I temporarily redirect the output of the logger(s) that spit out to stdout and capture them? I took a look at logging/init.py, but it doesn't immediately tell me what I need to do.
My motivation for doing this is that I want to equip a crufty big codebase with tests, each of which captures the spurious amounts of logging output that each test invokes. I can capture external programs, but I can't seem to capture the tests that I run inside nose.
Rewriting the verbose parts isn't an option right now, but is definitely a goal for further down the road.
Edit, regarding ubuntu
Here's what I've tried running with nosetests:
from __future__ import print_function
import sysdef test_funky_shurane():import logginglogging.basicConfig(level=logging.DEBUG)logging.info("===== shurane info")logging.warn("===== shurane warn")logging.error("===== shurane error")logging.critical("===== shurane critical")print("===== shurane stdout", file=sys.stdout)print("===== shurane stderr", file=sys.stderr)assert True
And then running the above with:
nosetests test_logging.py
nosetests --nocapture test_logging.py