27

I have the impression (but do not find the documentation for it) that unittest sets the logging level to WARNING for all loggers. I would like to:

  • be able to specify the logging level for all loggers, from the command line (when running the tests) or from the test module itself
  • avoid unittest messing around with the application logging level: when running the tests I want to have the same logging output (same levels) as when running the application

How can I achieve this?

blueFast
  • 41,341
  • 63
  • 198
  • 344
  • 3
    As usual, can you give a minimal but complete example, with the expected and actual output? – Ulrich Eckhardt May 19 '16 at 06:21
  • Any chance you've found an answer by now? Would you care to share? In my case, only `INFO` log messages show up and I wanna see `DEBUG` messages also. – pmlk Jun 18 '18 at 18:53
  • @dan-j could you provide a minimum example that reproduces your issue? – Kamil Niski Oct 14 '18 at 12:13
  • Most probably the issue is that the logging configuration code is simply not called from the test code, resulting in different logger setups in test and production modes. – hoefling Oct 14 '18 at 20:25
  • @Kamil I just tried to create a minimal reproducible example, and I wasn't able to. :-/ Here's what I created: https://github.com/daj/python-unittest-example The logs get written whenever I run the tests. However, my more complex project does still hit this issue. I've tried making the project layout more similar, and adding in similar dependencies, but I still can't make my example project fail. At this rate, once I've reproduced the problem I will probably have diagnosed it too... – Dan J Oct 15 '18 at 02:11
  • 3
    No, `unittest` does not do any automatic alteration of logging levels. Period. – Martijn Pieters Oct 16 '18 at 16:19
  • 2
    More likely is that your production code runs a piece of code that configures logging, that your unittests are not running. The absence of configuration means that defaults apply. That's not the same thing as the unittest altering configuration. – Martijn Pieters Oct 16 '18 at 16:20
  • Your impression might come from pytest which is a python testing framework that isn't part of the standard library. From [the pytest logging documentation](https://docs.pytest.org/en/latest/logging.html): "pytest captures log messages of level WARNING or above automatically and displays them in their own section for each failed test in the same manner as captured stdout and stderr." – Tony Aug 15 '19 at 16:43

5 Answers5

14

I don't believe unittest itself does anything to logging, unless you use a _CapturingHandler class which it defines. This simple program demonstrates:

import logging
import unittest

logger = logging.getLogger(__name__)

class MyTestCase(unittest.TestCase):
    def test_something(self):
        logger.debug('logged from test_something')


if __name__ == '__main__':
    # DEBUG for demonstration purposes, but you could set the level from
    # cmdline args to whatever you like
    logging.basicConfig(level=logging.DEBUG, format='%(name)s %(levelname)s %(message)s')
    unittest.main()

When run, it prints

__main__ DEBUG logged from test_something
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

showing that it is logging events at DEBUG level, as expected. So the problem is likely to be related to something else, e.g. the code under test, or some other test runner which changes the logging configuration or redirects sys.stdout and sys.stderr. You will probably need to provide more information about your test environment, or better yet a minimal program that demonstrates the problem (as my example above shows that unittest by itself doesn't cause the problem you're describing).

Vinay Sajip
  • 95,872
  • 14
  • 179
  • 191
8

See below example for logging in Python. Also you can change LOG_LEVEL using 'setLevel' method.

import os
import logging

logging.basicConfig()
logger = logging.getLogger(__name__)

# Change logging level here.
logger.setLevel(os.environ.get('LOG_LEVEL', logging.INFO))

logger.info('For INFO message')
logger.debug('For DEBUG message')
logger.warning('For WARNING message')
logger.error('For ERROR message')
logger.critical('For CRITICAL message')
mareoraft
  • 3,474
  • 4
  • 26
  • 62
Hassan Mehmood
  • 1,414
  • 1
  • 14
  • 22
  • 11
    This is indeed how the python logging framework is set up. But OP is hinting that this does not work when unittest is involved. unittest apparantly messes things up for him, so _why_ and _how_ and _what to do_? – Ytsen de Boer Mar 05 '18 at 13:37
  • logger.warn() is deprecated. You should now use logger.warning() – Edwarric Dec 15 '19 at 15:27
0

This is in addition to @Vinay's answer above. It does not answer the original question. I wanted to include command line options for modifying the log level. The intent was to get detailed loggin only when I pass a certain parameter from the command line. This is how I solved it:

import sys
import unittest
import logging
from histogram import Histogram
class TestHistogram(unittest.TestCase):

def test_case2(self):
    h = Histogram([2,1,2])
    self.assertEqual(h.calculateMaxAreaON(), 3)

if __name__ == '__main__':
    argv = len(sys.argv) > 1 and sys.argv[1]
    loglevel = logging.INFO if argv == '-v' else logging.WARNING
    logging.basicConfig(level=loglevel)
    unittest.main() 

The intent is to get more verbose logging. I know it does not answer the question, but I'll leave it here in case someone comes looking for a similar requirement such as this.

Raj Kumar
  • 1,547
  • 14
  • 19
0

this worked for me:

logging.basicConfig(level=logging.DEBUG)

And if I wanted a specific format:

logging.basicConfig(
    level=logging.DEBUG,
    datefmt="%H:%M:%S",
    format="%(asctime)s.%(msecs)03d [%(levelname)-5s] %(message)s",
)
gMale
  • 17,147
  • 17
  • 91
  • 116
0

Programmatically:

Put this line of code in each test function defined in your class that you want to set the logging level:

logging.getLogger().setLevel(logging.INFO)

Ex. class:

import unittest
import logging


class ExampleTest(unittest.TestCase):
    def test_method(self):
        logging.getLogger().setLevel(logging.INFO)
        ...

Command Line:

This example just shows how to do it in a normal script, not specific to unittest example. Capturing the log level via command line, using argparse for arguments:

import logging
import argparse

...

def parse_args():
    parser = argparse.ArgumentParser(description='...')
    parser.add_argument('-v', '--verbose', help='enable verbose logging', action='store_const', dest="loglevel", const=logging.INFO, default=logging.WARNING)

...

def main():
    args = parse_args()
    logging.getLogger().setLevel(args.loglevel)
Dwigt
  • 729
  • 6
  • 16