How can I temporarily redirect the output of logging in Python?

2024/10/2 3:18:39

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
Answer

the logging.basicConfig() is a convenience that sets up some logger handling in a very simple way. If you need a little more than that, you shouldn't use basicConfig(). That's not a big deal, because it doesn't do a whole lot. What we need is to configure logging for both streams;

import logging, sys
fmt = logging.Formatter(BASIC_FORMAT)hdlr_stderr = logging.StreamHandler(sys.stderr)
hdlr_stderr.setFormatter(fmt)
hdlr_stdout = logging.StreamHandler(sys.stdout)
hdlr_stdout.setFormatter(fmt)
root.addHandler(hdlr_stderr)
root.addHandler(hdlr_stdout)
root.setLevel(logging.DEBUG)

By default, loggers log all messages that they receive; but initially, we don't want to log any messages to sys.stdout:

hdlr_stdout.level = float('inf')  # larger than any log level; nothing gets logged

Then, your context manager might look a bit like:

@contextlib.contextmanager
def redirect_stderr_logging(where):hdlr_stderr.level = float('inf')hdlr_stdout.level = logging.NOTSETtry:yield wherefinally:hdlr_stderr.level = logging.NOTSEThdlr_stdout.level = float('inf')
https://en.xdnf.cn/q/70892.html

Related Q&A

trouble with creating a virtual environment in Windows 8, python 3.3

Im trying to create a virtual environment in Python, but I always get an error no matter how many times I re-install python-setuptools and pip. My computer is running Windows 8, and Im using Python 3.3…

Python imaplib search email with date and time

Im trying to read all emails from a particular date and time. mail = imaplib.IMAP4_SSL(self.url, self.port) mail.login(user, password) mail.select(self.folder) since = datetime.strftime(since, %d-%b-%Y…

cumsum() on multi-index pandas dataframe

I have a multi-index dataframe that shows the sum of transactions on a monthly frequency. I am trying to get a cumsum() on yearly basis that respects my mapid and service multi-index. However I dont kn…

Python SSL Certification Problems in Tensorflow

Im trying to download the MNIST data which is supposedly handled in: tensorflow.examples.tutorials.mnist.input_data.read_data_sets() As far as Im aware read_data_sets sends a pull request to a server t…

How do I get a python program to run instead of opening in Notepad?

I am having some trouble with opening a .py file. I have a program that calls this .py file (i.e. pathname/example.py file.txt), but instead of running the python program, it opens it in Notepad. How t…

How to find a keys value from a list of dictionaries?

How do I get a given keys value from a list of dictionaries? mylist = [{powerpoint_color: blue,client_name: Sport Parents (Regrouped)},{sort_order: ascending,chart_layout: 1,chart_type: bar} ]The numb…

Wandering star - codeabbey task

Im trying to solve this problem and Im not sure what to do next. Link to the problem Problem statement: Suppose that some preliminary image preprocessing was already done and you have data in form of …

Find delimiter in txt to convert to csv using Python

I have to convert some txt files to csv (and make some operation during the conversion).I use csv.Sniffer() class to detect wich delimiter is used in the txt This codewith open(filename_input, r) as f1…

Assert mocked function called with json string in python

Writing some unit tests in python and using MagicMock to mock out a method that accepts a JSON string as input. In my unit test, I want to assert that it is called with given arguments, however I run i…

read certificate(.crt) and key(.key) file in python

So im using the JIRA-Python module to connect to my companys instance on JIRA and it requires me to pass the certificate and key for this. However using the OpenSSL module,im unable to read my local ce…