From: Ben Darnell Date: Wed, 19 Feb 2014 04:15:19 +0000 (-0500) Subject: Document the fact that tornado.options configures logging by default. X-Git-Tag: v4.0.0b1~116 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2dc57c57b1a4e64e0c10796718f54f0792968dba;p=thirdparty%2Ftornado.git Document the fact that tornado.options configures logging by default. Add tests and comments for how to disable this configuration. Make it slightly easier to disable by making the command line flag case-insensitive and allowing `None` instead of the string "none" when setting the flag in code. Closes #952. --- diff --git a/tornado/log.py b/tornado/log.py index 36c3dd408..306220cd2 100644 --- a/tornado/log.py +++ b/tornado/log.py @@ -184,7 +184,7 @@ def enable_pretty_logging(options=None, logger=None): """ if options is None: from tornado.options import options - if options.logging == 'none': + if options.logging is None or options.logging.lower() == 'none': return if logger is None: logger = logging.getLogger() diff --git a/tornado/options.py b/tornado/options.py index 1105c0e9a..fa9c269ea 100644 --- a/tornado/options.py +++ b/tornado/options.py @@ -56,6 +56,18 @@ We support `datetimes `, `timedeltas the top-level functions in this module (`define`, `parse_command_line`, etc) simply call methods on it. You may create additional `OptionParser` instances to define isolated sets of options, such as for subcommands. + +.. note:: + + By default, several options are defined that will configure the + standard `logging` module when `parse_command_line` or `parse_config_file` + are called. If you want Tornado to leave the logging configuration + alone so you can manage it yourself, either pass ``--logging=none`` + on the command line or do the following to disable it in code:: + + from tornado.options import options, parse_command_line + options.logging = None + parse_command_line() """ from __future__ import absolute_import, division, print_function, with_statement @@ -360,6 +372,8 @@ class _Mockable(object): class _Option(object): + UNSET = object() + def __init__(self, name, default=None, type=basestring_type, help=None, metavar=None, multiple=False, file_name=None, group_name=None, callback=None): @@ -374,10 +388,10 @@ class _Option(object): self.group_name = group_name self.callback = callback self.default = default - self._value = None + self._value = _Option.UNSET def value(self): - return self.default if self._value is None else self._value + return self.default if self._value is _Option.UNSET else self._value def parse(self, value): _parse = { diff --git a/tornado/test/log_test.py b/tornado/test/log_test.py index d60cbad47..ee832c541 100644 --- a/tornado/test/log_test.py +++ b/tornado/test/log_test.py @@ -20,6 +20,8 @@ import glob import logging import os import re +import subprocess +import sys import tempfile import warnings @@ -156,3 +158,50 @@ class EnablePrettyLoggingTest(unittest.TestCase): for filename in glob.glob(tmpdir + '/test_log*'): os.unlink(filename) os.rmdir(tmpdir) + + +class LoggingOptionTest(unittest.TestCase): + """Test the ability to enable and disable Tornado's logging hooks.""" + def logs_present(self, statement, args=None): + # Each test may manipulate and/or parse the options and then logs + # a line at the 'info' level. This level is ignored in the + # logging module by default, but Tornado turns it on by default + # so it is the easiest way to tell whether tornado's logging hooks + # ran. + IMPORT = 'from tornado.options import options, parse_command_line' + LOG_INFO = 'import logging; logging.info("hello")' + program = ';'.join([IMPORT, statement, LOG_INFO]) + proc = subprocess.Popen( + [sys.executable, '-c', program] + (args or []), + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, stderr = proc.communicate() + self.assertEqual(proc.returncode, 0, 'process failed: %r' % stdout) + return b'hello' in stdout + + def test_default(self): + self.assertFalse(self.logs_present('pass')) + + def test_tornado_default(self): + self.assertTrue(self.logs_present('parse_command_line()')) + + def test_disable_command_line(self): + self.assertFalse(self.logs_present('parse_command_line()', + ['--logging=none'])) + + def test_disable_command_line_case_insensitive(self): + self.assertFalse(self.logs_present('parse_command_line()', + ['--logging=None'])) + + def test_disable_code_string(self): + self.assertFalse(self.logs_present( + 'options.logging = "none"; parse_command_line()')) + + def test_disable_code_none(self): + self.assertFalse(self.logs_present( + 'options.logging = None; parse_command_line()')) + + def test_disable_override(self): + # command line trumps code defaults + self.assertTrue(self.logs_present( + 'options.logging = None; parse_command_line()', + ['--logging=info']))