]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Document the fact that tornado.options configures logging by default.
authorBen Darnell <ben@bendarnell.com>
Wed, 19 Feb 2014 04:15:19 +0000 (23:15 -0500)
committerBen Darnell <ben@bendarnell.com>
Wed, 19 Feb 2014 04:35:55 +0000 (23:35 -0500)
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.

tornado/log.py
tornado/options.py
tornado/test/log_test.py

index 36c3dd408ab060e42778acc400621352447023ad..306220cd24fc12ec2bf5ca3f694e993ec9449cd0 100644 (file)
@@ -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()
index 1105c0e9a45b35f2d1d86fab08c9d9094e8b35d7..fa9c269ea7d093701af328d8f93a25812d56edb8 100644 (file)
@@ -56,6 +56,18 @@ We support `datetimes <datetime.datetime>`, `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 = {
index d60cbad471f5c6b16ac76fd5f214994dc7f2d126..ee832c54112332b72f845627c7d84fa6e4d75668 100644 (file)
@@ -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']))