{
    "file_diffs": [
        {
            "old_file_content": "#!/usr/bin/env python\n#\n# Copyright 2012 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\"\"\"Logging support for Tornado.\n\nTornado uses three logger streams:\n\n* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and\n  potentially other servers in the future)\n* ``tornado.application``: Logging of errors from application code (i.e.\n  uncaught exceptions from callbacks)\n* ``tornado.general``: General-purpose logging, including any errors\n  or warnings from Tornado itself.\n\nThese streams may be configured independently using the standard library's\n`logging` module.  For example, you may wish to send ``tornado.access`` logs\nto a separate file for analysis.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport logging\nimport logging.handlers\nimport sys\n\nfrom tornado.escape import _unicode\nfrom tornado.util import unicode_type, basestring_type\n\ntry:\n    import curses\nexcept ImportError:\n    curses = None\n\n# Logger objects for internal tornado use\naccess_log = logging.getLogger(\"tornado.access\")\napp_log = logging.getLogger(\"tornado.application\")\ngen_log = logging.getLogger(\"tornado.general\")\n\n\ndef _stderr_supports_color():\n    color = False\n    if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():\n        try:\n            curses.setupterm()\n            if curses.tigetnum(\"colors\") > 0:\n                color = True\n        except Exception:\n            pass\n    return color\n\n\ndef _safe_unicode(s):\n    try:\n        return _unicode(s)\n    except UnicodeDecodeError:\n        return repr(s)\n\n\nclass LogFormatter(logging.Formatter):\n    \"\"\"Log formatter used in Tornado.\n\n    Key features of this formatter are:\n\n    * Color support when logging to a terminal that supports it.\n    * Timestamps on every log line.\n    * Robust against str/bytes encoding problems.\n\n    This formatter is enabled automatically by\n    `tornado.options.parse_command_line` (unless ``--logging=none`` is\n    used).\n    \"\"\"\n    DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'\n    DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'\n    DEFAULT_COLORS = {\n        logging.DEBUG: 4,  # Blue\n        logging.INFO: 2,  # Green\n        logging.WARNING: 3,  # Yellow\n        logging.ERROR: 1,  # Red\n    }\n\n    def __init__(self, color=True, fmt=DEFAULT_FORMAT,\n                 datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):\n        r\"\"\"\n        :arg bool color: Enables color support.\n        :arg string fmt: Log message format.\n          It will be applied to the attributes dict of log records. The\n          text between ``%(color)s`` and ``%(end_color)s`` will be colored\n          depending on the level if color support is on.\n        :arg dict colors: color mappings from logging level to terminal color\n          code\n        :arg string datefmt: Datetime format.\n          Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.\n\n        .. versionchanged:: 3.2\n\n           Added ``fmt`` and ``datefmt`` arguments.\n        \"\"\"\n        logging.Formatter.__init__(self, datefmt=datefmt)\n        self._fmt = fmt\n\n        self._colors = {}\n        if color and _stderr_supports_color():\n            # The curses module has some str/bytes confusion in\n            # python3.  Until version 3.2.3, most methods return\n            # bytes, but only accept strings.  In addition, we want to\n            # output these strings with the logging module, which\n            # works with unicode strings.  The explicit calls to\n            # unicode() below are harmless in python2 but will do the\n            # right conversion in python 3.\n            fg_color = (curses.tigetstr(\"setaf\") or\n                        curses.tigetstr(\"setf\") or \"\")\n            if (3, 0) < sys.version_info < (3, 2, 3):\n                fg_color = unicode_type(fg_color, \"ascii\")\n\n            for levelno, code in colors.items():\n                self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), \"ascii\")\n            self._normal = unicode_type(curses.tigetstr(\"sgr0\"), \"ascii\")\n        else:\n            self._normal = ''\n\n    def format(self, record):\n        try:\n            message = record.getMessage()\n            assert isinstance(message, basestring_type)  # guaranteed by logging\n            # Encoding notes:  The logging module prefers to work with character\n            # strings, but only enforces that log messages are instances of\n            # basestring.  In python 2, non-ascii bytestrings will make\n            # their way through the logging framework until they blow up with\n            # an unhelpful decoding error (with this formatter it happens\n            # when we attach the prefix, but there are other opportunities for\n            # exceptions further along in the framework).\n            #\n            # If a byte string makes it this far, convert it to unicode to\n            # ensure it will make it out to the logs.  Use repr() as a fallback\n            # to ensure that all byte strings can be converted successfully,\n            # but don't do it by default so we don't add extra quotes to ascii\n            # bytestrings.  This is a bit of a hacky place to do this, but\n            # it's worth it since the encoding errors that would otherwise\n            # result are so useless (and tornado is fond of using utf8-encoded\n            # byte strings whereever possible).\n            record.message = _safe_unicode(message)\n        except Exception as e:\n            record.message = \"Bad message (%r): %r\" % (e, record.__dict__)\n\n        record.asctime = self.formatTime(record, self.datefmt)\n\n        if record.levelno in self._colors:\n            record.color = self._colors[record.levelno]\n            record.end_color = self._normal\n        else:\n            record.color = record.end_color = ''\n\n        formatted = self._fmt % record.__dict__\n\n        if record.exc_info:\n            if not record.exc_text:\n                record.exc_text = self.formatException(record.exc_info)\n        if record.exc_text:\n            # exc_text contains multiple lines.  We need to _safe_unicode\n            # each line separately so that non-utf8 bytes don't cause\n            # all the newlines to turn into '\\n'.\n            lines = [formatted.rstrip()]\n            lines.extend(_safe_unicode(ln) for ln in record.exc_text.split('\\n'))\n            formatted = '\\n'.join(lines)\n        return formatted.replace(\"\\n\", \"\\n    \")\n\n\ndef enable_pretty_logging(options=None, logger=None):\n    \"\"\"Turns on formatted logging output as configured.\n\n    This is called automatically by `tornado.options.parse_command_line`\n    and `tornado.options.parse_config_file`.\n    \"\"\"\n    if options is None:\n        from tornado.options import options\n    if options.logging is None or options.logging.lower() == 'none':\n        return\n    if logger is None:\n        logger = logging.getLogger()\n    logger.setLevel(getattr(logging, options.logging.upper()))\n    if options.log_file_prefix:\n        channel = logging.handlers.RotatingFileHandler(\n            filename=options.log_file_prefix,\n            maxBytes=options.log_file_max_size,\n            backupCount=options.log_file_num_backups)\n        channel.setFormatter(LogFormatter(color=False))\n        logger.addHandler(channel)\n\n    if (options.log_to_stderr or\n            (options.log_to_stderr is None and not logger.handlers)):\n        # Set up color if we are in a tty and curses is installed\n        channel = logging.StreamHandler()\n        channel.setFormatter(LogFormatter())\n        logger.addHandler(channel)\n\n\ndef define_logging_options(options=None):\n    \"\"\"Add logging-related flags to ``options``.\n\n    These options are present automatically on the default options instance;\n    this method is only necessary if you have created your own `.OptionParser`.\n\n    .. versionadded:: 4.2\n        This function existed in prior versions but was broken and undocumented until 4.2.\n    \"\"\"\n    if options is None:\n        # late import to prevent cycle\n        from tornado.options import options\n    options.define(\"logging\", default=\"info\",\n                   help=(\"Set the Python log level. If 'none', tornado won't touch the \"\n                         \"logging configuration.\"),\n                   metavar=\"debug|info|warning|error|none\")\n    options.define(\"log_to_stderr\", type=bool, default=None,\n                   help=(\"Send log output to stderr (colorized if possible). \"\n                         \"By default use stderr if --log_file_prefix is not set and \"\n                         \"no other logging is configured.\"))\n    options.define(\"log_file_prefix\", type=str, default=None, metavar=\"PATH\",\n                   help=(\"Path prefix for log files. \"\n                         \"Note that if you are running multiple tornado processes, \"\n                         \"log_file_prefix must be different for each of them (e.g. \"\n                         \"include the port number)\"))\n    options.define(\"log_file_max_size\", type=int, default=100 * 1000 * 1000,\n                   help=\"max size of log files before rollover\")\n    options.define(\"log_file_num_backups\", type=int, default=10,\n                   help=\"number of log files to keep\")\n\n    options.add_parse_callback(lambda: enable_pretty_logging(options))\n",
            "new_file_content": "#!/usr/bin/env python\n#\n# Copyright 2012 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\"\"\"Logging support for Tornado.\n\nTornado uses three logger streams:\n\n* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and\n  potentially other servers in the future)\n* ``tornado.application``: Logging of errors from application code (i.e.\n  uncaught exceptions from callbacks)\n* ``tornado.general``: General-purpose logging, including any errors\n  or warnings from Tornado itself.\n\nThese streams may be configured independently using the standard library's\n`logging` module.  For example, you may wish to send ``tornado.access`` logs\nto a separate file for analysis.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport logging\nimport logging.handlers\nimport sys\n\nfrom tornado.escape import _unicode\nfrom tornado.util import unicode_type, basestring_type\n\ntry:\n    import curses\nexcept ImportError:\n    curses = None\n\n# Logger objects for internal tornado use\naccess_log = logging.getLogger(\"tornado.access\")\napp_log = logging.getLogger(\"tornado.application\")\ngen_log = logging.getLogger(\"tornado.general\")\n\n\ndef _stderr_supports_color():\n    color = False\n    if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():\n        try:\n            curses.setupterm()\n            if curses.tigetnum(\"colors\") > 0:\n                color = True\n        except Exception:\n            pass\n    return color\n\n\ndef _safe_unicode(s):\n    try:\n        return _unicode(s)\n    except UnicodeDecodeError:\n        return repr(s)\n\n\nclass LogFormatter(logging.Formatter):\n    \"\"\"Log formatter used in Tornado.\n\n    Key features of this formatter are:\n\n    * Color support when logging to a terminal that supports it.\n    * Timestamps on every log line.\n    * Robust against str/bytes encoding problems.\n\n    This formatter is enabled automatically by\n    `tornado.options.parse_command_line` (unless ``--logging=none`` is\n    used).\n    \"\"\"\n    DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'\n    DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'\n    DEFAULT_COLORS = {\n        logging.DEBUG: 4,  # Blue\n        logging.INFO: 2,  # Green\n        logging.WARNING: 3,  # Yellow\n        logging.ERROR: 1,  # Red\n    }\n\n    def __init__(self, color=True, fmt=DEFAULT_FORMAT,\n                 datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):\n        r\"\"\"\n        :arg bool color: Enables color support.\n        :arg string fmt: Log message format.\n          It will be applied to the attributes dict of log records. The\n          text between ``%(color)s`` and ``%(end_color)s`` will be colored\n          depending on the level if color support is on.\n        :arg dict colors: color mappings from logging level to terminal color\n          code\n        :arg string datefmt: Datetime format.\n          Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.\n\n        .. versionchanged:: 3.2\n\n           Added ``fmt`` and ``datefmt`` arguments.\n        \"\"\"\n        logging.Formatter.__init__(self, datefmt=datefmt)\n        self._fmt = fmt\n\n        self._colors = {}\n        if color and _stderr_supports_color():\n            # The curses module has some str/bytes confusion in\n            # python3.  Until version 3.2.3, most methods return\n            # bytes, but only accept strings.  In addition, we want to\n            # output these strings with the logging module, which\n            # works with unicode strings.  The explicit calls to\n            # unicode() below are harmless in python2 but will do the\n            # right conversion in python 3.\n            fg_color = (curses.tigetstr(\"setaf\") or\n                        curses.tigetstr(\"setf\") or \"\")\n            if (3, 0) < sys.version_info < (3, 2, 3):\n                fg_color = unicode_type(fg_color, \"ascii\")\n\n            for levelno, code in colors.items():\n                self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), \"ascii\")\n            self._normal = unicode_type(curses.tigetstr(\"sgr0\"), \"ascii\")\n        else:\n            self._normal = ''\n\n    def format(self, record):\n        try:\n            message = record.getMessage()\n            assert isinstance(message, basestring_type)  # guaranteed by logging\n            # Encoding notes:  The logging module prefers to work with character\n            # strings, but only enforces that log messages are instances of\n            # basestring.  In python 2, non-ascii bytestrings will make\n            # their way through the logging framework until they blow up with\n            # an unhelpful decoding error (with this formatter it happens\n            # when we attach the prefix, but there are other opportunities for\n            # exceptions further along in the framework).\n            #\n            # If a byte string makes it this far, convert it to unicode to\n            # ensure it will make it out to the logs.  Use repr() as a fallback\n            # to ensure that all byte strings can be converted successfully,\n            # but don't do it by default so we don't add extra quotes to ascii\n            # bytestrings.  This is a bit of a hacky place to do this, but\n            # it's worth it since the encoding errors that would otherwise\n            # result are so useless (and tornado is fond of using utf8-encoded\n            # byte strings whereever possible).\n            record.message = _safe_unicode(message)\n        except Exception as e:\n            record.message = \"Bad message (%r): %r\" % (e, record.__dict__)\n\n        record.asctime = self.formatTime(record, self.datefmt)\n\n        if record.levelno in self._colors:\n            record.color = self._colors[record.levelno]\n            record.end_color = self._normal\n        else:\n            record.color = record.end_color = ''\n\n        formatted = self._fmt % record.__dict__\n\n        if record.exc_info:\n            if not record.exc_text:\n                record.exc_text = self.formatException(record.exc_info)\n        if record.exc_text:\n            # exc_text contains multiple lines.  We need to _safe_unicode\n            # each line separately so that non-utf8 bytes don't cause\n            # all the newlines to turn into '\\n'.\n            lines = [formatted.rstrip()]\n            lines.extend(_safe_unicode(ln) for ln in record.exc_text.split('\\n'))\n            formatted = '\\n'.join(lines)\n        return formatted.replace(\"\\n\", \"\\n    \")\n\n\ndef enable_pretty_logging(options=None, logger=None):\n    \"\"\"Turns on formatted logging output as configured.\n\n    This is called automatically by `tornado.options.parse_command_line`\n    and `tornado.options.parse_config_file`.\n    \"\"\"\n    if options is None:\n        from tornado.options import options\n    if options.logging is None or options.logging.lower() == 'none':\n        return\n    if logger is None:\n        logger = logging.getLogger()\n    logger.setLevel(getattr(logging, options.logging.upper()))\n    if options.log_file_prefix:\n        if options.rotating_mode == 'sized':\n            channel = logging.handlers.RotatingFileHandler(\n                filename=options.log_file_prefix,\n                maxBytes=options.log_file_max_size,\n                backupCount=options.log_file_num_backups)\n        elif options.rotating_mode == 'timed':\n            channel = logging.handlers.TimedRotatingFileHandler(\n                filename=options.log_file_prefix,\n                when=options.log_file_rotating_when,\n                interval=options.log_file_rotating_interval,\n                backupCount=options.log_file_num_backups)\n        else:\n            channel = logging.NullHandler()\n        channel.setFormatter(LogFormatter(color=False))\n        logger.addHandler(channel)\n\n    if (options.log_to_stderr or\n            (options.log_to_stderr is None and not logger.handlers)):\n        # Set up color if we are in a tty and curses is installed\n        channel = logging.StreamHandler()\n        channel.setFormatter(LogFormatter())\n        logger.addHandler(channel)\n\n\ndef define_logging_options(options=None):\n    \"\"\"Add logging-related flags to ``options``.\n\n    These options are present automatically on the default options instance;\n    this method is only necessary if you have created your own `.OptionParser`.\n\n    .. versionadded:: 4.2\n        This function existed in prior versions but was broken and undocumented until 4.2.\n    \"\"\"\n    if options is None:\n        # late import to prevent cycle\n        from tornado.options import options\n    options.define(\"logging\", default=\"info\",\n                   help=(\"Set the Python log level. If 'none', tornado won't touch the \"\n                         \"logging configuration.\"),\n                   metavar=\"debug|info|warning|error|none\")\n    options.define(\"log_to_stderr\", type=bool, default=None,\n                   help=(\"Send log output to stderr (colorized if possible). \"\n                         \"By default use stderr if --log_file_prefix is not set and \"\n                         \"no other logging is configured.\"))\n    options.define(\"log_file_prefix\", type=str, default=None, metavar=\"PATH\",\n                   help=(\"Path prefix for log files. \"\n                         \"Note that if you are running multiple tornado processes, \"\n                         \"log_file_prefix must be different for each of them (e.g. \"\n                         \"include the port number)\"))\n    options.define(\"log_file_max_size\", type=int, default=100 * 1000 * 1000,\n                   help=\"max size of log files before rollover\")\n    options.define(\"log_file_num_backups\", type=int, default=10,\n                   help=\"number of log files to keep\")\n\n    options.define(\"log_file_rotating_when\", type=str, default='midnight',\n                   help=(\"specify the type of TimedRotatingFileHandler interval \"\n                         \"other options:('S', 'M', 'H', 'D', 'W0'-'W6')\"))\n    options.define(\"log_file_rotating_interval\", type=int, default=1,\n                   help=\"The interval value of timed rotating\")\n\n    options.define(\"rotating_mode\", type=str, default='sized',\n                   help=\"The mode of rotating files(timed or sized)\")\n\n    options.add_parse_callback(lambda: enable_pretty_logging(options))\n",
            "header": {
                "file": {
                    "path": "tornado/log.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "c68dec46",
                "new_commit_hash": "b72c5ba8",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tornado/log.py"
            },
            "plus_file": {
                "path": "b/tornado/log.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 190,
                            "length": 10
                        },
                        "new_range": {
                            "start": 190,
                            "length": 19
                        },
                        "section": "def enable_pretty_logging(options=None, logger=None):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        logger = logging.getLogger()",
                                "type": "context"
                            },
                            {
                                "content": "    logger.setLevel(getattr(logging, options.logging.upper()))",
                                "type": "context"
                            },
                            {
                                "content": "    if options.log_file_prefix:",
                                "type": "context"
                            },
                            {
                                "content": "        channel = logging.handlers.RotatingFileHandler(",
                                "type": "deleted"
                            },
                            {
                                "content": "            filename=options.log_file_prefix,",
                                "type": "deleted"
                            },
                            {
                                "content": "            maxBytes=options.log_file_max_size,",
                                "type": "deleted"
                            },
                            {
                                "content": "            backupCount=options.log_file_num_backups)",
                                "type": "deleted"
                            },
                            {
                                "content": "        if options.rotating_mode == 'sized':",
                                "type": "added"
                            },
                            {
                                "content": "            channel = logging.handlers.RotatingFileHandler(",
                                "type": "added"
                            },
                            {
                                "content": "                filename=options.log_file_prefix,",
                                "type": "added"
                            },
                            {
                                "content": "                maxBytes=options.log_file_max_size,",
                                "type": "added"
                            },
                            {
                                "content": "                backupCount=options.log_file_num_backups)",
                                "type": "added"
                            },
                            {
                                "content": "        elif options.rotating_mode == 'timed':",
                                "type": "added"
                            },
                            {
                                "content": "            channel = logging.handlers.TimedRotatingFileHandler(",
                                "type": "added"
                            },
                            {
                                "content": "                filename=options.log_file_prefix,",
                                "type": "added"
                            },
                            {
                                "content": "                when=options.log_file_rotating_when,",
                                "type": "added"
                            },
                            {
                                "content": "                interval=options.log_file_rotating_interval,",
                                "type": "added"
                            },
                            {
                                "content": "                backupCount=options.log_file_num_backups)",
                                "type": "added"
                            },
                            {
                                "content": "        else:",
                                "type": "added"
                            },
                            {
                                "content": "            channel = logging.NullHandler()",
                                "type": "added"
                            },
                            {
                                "content": "        channel.setFormatter(LogFormatter(color=False))",
                                "type": "context"
                            },
                            {
                                "content": "        logger.addHandler(channel)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/log.py",
                            "type": "function",
                            "name": "enable_pretty_logging",
                            "content": "def enable_pretty_logging(options=None, logger=None):\n    \"\"\"Turns on formatted logging output as configured.\n\n    This is called automatically by `tornado.options.parse_command_line`\n    and `tornado.options.parse_config_file`.\n    \"\"\"\n    if options is None:\n        from tornado.options import options\n    if options.logging is None or options.logging.lower() == 'none':\n        return\n    if logger is None:\n        logger = logging.getLogger()\n    logger.setLevel(getattr(logging, options.logging.upper()))\n    if options.log_file_prefix:\n        channel = logging.handlers.RotatingFileHandler(\n            filename=options.log_file_prefix,\n            maxBytes=options.log_file_max_size,\n            backupCount=options.log_file_num_backups)\n        channel.setFormatter(LogFormatter(color=False))\n        logger.addHandler(channel)\n\n    if (options.log_to_stderr or\n            (options.log_to_stderr is None and not logger.handlers)):\n        # Set up color if we are in a tty and curses is installed\n        channel = logging.StreamHandler()\n        channel.setFormatter(LogFormatter())\n        logger.addHandler(channel)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 179,
                            "end_lineno": 205,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 235,
                            "length": 4
                        },
                        "new_range": {
                            "start": 244,
                            "length": 13
                        },
                        "section": "def define_logging_options(options=None):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    options.define(\"log_file_num_backups\", type=int, default=10,",
                                "type": "context"
                            },
                            {
                                "content": "                   help=\"number of log files to keep\")",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    options.define(\"log_file_rotating_when\", type=str, default='midnight',",
                                "type": "added"
                            },
                            {
                                "content": "                   help=(\"specify the type of TimedRotatingFileHandler interval \"",
                                "type": "added"
                            },
                            {
                                "content": "                         \"other options:('S', 'M', 'H', 'D', 'W0'-'W6')\"))",
                                "type": "added"
                            },
                            {
                                "content": "    options.define(\"log_file_rotating_interval\", type=int, default=1,",
                                "type": "added"
                            },
                            {
                                "content": "                   help=\"The interval value of timed rotating\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    options.define(\"rotating_mode\", type=str, default='sized',",
                                "type": "added"
                            },
                            {
                                "content": "                   help=\"The mode of rotating files(timed or sized)\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    options.add_parse_callback(lambda: enable_pretty_logging(options))",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/log.py",
                            "type": "function",
                            "name": "define_logging_options",
                            "content": "def define_logging_options(options=None):\n    \"\"\"Add logging-related flags to ``options``.\n\n    These options are present automatically on the default options instance;\n    this method is only necessary if you have created your own `.OptionParser`.\n\n    .. versionadded:: 4.2\n        This function existed in prior versions but was broken and undocumented until 4.2.\n    \"\"\"\n    if options is None:\n        # late import to prevent cycle\n        from tornado.options import options\n    options.define(\"logging\", default=\"info\",\n                   help=(\"Set the Python log level. If 'none', tornado won't touch the \"\n                         \"logging configuration.\"),\n                   metavar=\"debug|info|warning|error|none\")\n    options.define(\"log_to_stderr\", type=bool, default=None,\n                   help=(\"Send log output to stderr (colorized if possible). \"\n                         \"By default use stderr if --log_file_prefix is not set and \"\n                         \"no other logging is configured.\"))\n    options.define(\"log_file_prefix\", type=str, default=None, metavar=\"PATH\",\n                   help=(\"Path prefix for log files. \"\n                         \"Note that if you are running multiple tornado processes, \"\n                         \"log_file_prefix must be different for each of them (e.g. \"\n                         \"include the port number)\"))\n    options.define(\"log_file_max_size\", type=int, default=100 * 1000 * 1000,\n                   help=\"max size of log files before rollover\")\n    options.define(\"log_file_num_backups\", type=int, default=10,\n                   help=\"number of log files to keep\")\n\n    options.define(\"log_file_rotating_when\", type=str, default='midnight',\n                   help=(\"specify the type of TimedRotatingFileHandler interval \"\n                         \"other options:('S', 'M', 'H', 'D', 'W0'-'W6')\"))\n    options.define(\"log_file_rotating_interval\", type=int, default=1,\n                   help=\"The interval value of timed rotating\")\n\n    options.define(\"rotating_mode\", type=str, default='sized',\n                   help=\"The mode of rotating files(timed or sized)\")\n\n    options.add_parse_callback(lambda: enable_pretty_logging(options))",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 217,
                            "end_lineno": 256,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#!/usr/bin/env python\n#\n# Copyright 2012 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport contextlib\nimport glob\nimport logging\nimport os\nimport re\nimport subprocess\nimport sys\nimport tempfile\nimport warnings\n\nfrom tornado.escape import utf8\nfrom tornado.log import LogFormatter, define_logging_options, enable_pretty_logging\nfrom tornado.options import OptionParser\nfrom tornado.test.util import unittest\nfrom tornado.util import u, basestring_type\n\n\n@contextlib.contextmanager\ndef ignore_bytes_warning():\n    with warnings.catch_warnings():\n        warnings.simplefilter('ignore', category=BytesWarning)\n        yield\n\n\nclass LogFormatterTest(unittest.TestCase):\n    # Matches the output of a single logging call (which may be multiple lines\n    # if a traceback was included, so we use the DOTALL option)\n    LINE_RE = re.compile(b\"(?s)\\x01\\\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\\\]\\x02 (.*)\")\n\n    def setUp(self):\n        self.formatter = LogFormatter(color=False)\n        # Fake color support.  We can't guarantee anything about the $TERM\n        # variable when the tests are run, so just patch in some values\n        # for testing.  (testing with color off fails to expose some potential\n        # encoding issues from the control characters)\n        self.formatter._colors = {\n            logging.ERROR: u(\"\\u0001\"),\n        }\n        self.formatter._normal = u(\"\\u0002\")\n        # construct a Logger directly to bypass getLogger's caching\n        self.logger = logging.Logger('LogFormatterTest')\n        self.logger.propagate = False\n        self.tempdir = tempfile.mkdtemp()\n        self.filename = os.path.join(self.tempdir, 'log.out')\n        self.handler = self.make_handler(self.filename)\n        self.handler.setFormatter(self.formatter)\n        self.logger.addHandler(self.handler)\n\n    def tearDown(self):\n        self.handler.close()\n        os.unlink(self.filename)\n        os.rmdir(self.tempdir)\n\n    def make_handler(self, filename):\n        # Base case: default setup without explicit encoding.\n        # In python 2, supports arbitrary byte strings and unicode objects\n        # that contain only ascii.  In python 3, supports ascii-only unicode\n        # strings (but byte strings will be repr'd automatically).\n        return logging.FileHandler(filename)\n\n    def get_output(self):\n        with open(self.filename, \"rb\") as f:\n            line = f.read().strip()\n            m = LogFormatterTest.LINE_RE.match(line)\n            if m:\n                return m.group(1)\n            else:\n                raise Exception(\"output didn't match regex: %r\" % line)\n\n    def test_basic_logging(self):\n        self.logger.error(\"foo\")\n        self.assertEqual(self.get_output(), b\"foo\")\n\n    def test_bytes_logging(self):\n        with ignore_bytes_warning():\n            # This will be \"\\xe9\" on python 2 or \"b'\\xe9'\" on python 3\n            self.logger.error(b\"\\xe9\")\n            self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n\n    def test_utf8_logging(self):\n        with ignore_bytes_warning():\n            self.logger.error(u(\"\\u00e9\").encode(\"utf8\"))\n        if issubclass(bytes, basestring_type):\n            # on python 2, utf8 byte strings (and by extension ascii byte\n            # strings) are passed through as-is.\n            self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n        else:\n            # on python 3, byte strings always get repr'd even if\n            # they're ascii-only, so this degenerates into another\n            # copy of test_bytes_logging.\n            self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n\n    def test_bytes_exception_logging(self):\n        try:\n            raise Exception(b'\\xe9')\n        except Exception:\n            self.logger.exception('caught exception')\n        # This will be \"Exception: \\xe9\" on python 2 or\n        # \"Exception: b'\\xe9'\" on python 3.\n        output = self.get_output()\n        self.assertRegexpMatches(output, br'Exception.*\\\\xe9')\n        # The traceback contains newlines, which should not have been escaped.\n        self.assertNotIn(br'\\n', output)\n\n\nclass UnicodeLogFormatterTest(LogFormatterTest):\n    def make_handler(self, filename):\n        # Adding an explicit encoding configuration allows non-ascii unicode\n        # strings in both python 2 and 3, without changing the behavior\n        # for byte strings.\n        return logging.FileHandler(filename, encoding=\"utf8\")\n\n    def test_unicode_logging(self):\n        self.logger.error(u(\"\\u00e9\"))\n        self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n\n\nclass EnablePrettyLoggingTest(unittest.TestCase):\n    def setUp(self):\n        super(EnablePrettyLoggingTest, self).setUp()\n        self.options = OptionParser()\n        define_logging_options(self.options)\n        self.logger = logging.Logger('tornado.test.log_test.EnablePrettyLoggingTest')\n        self.logger.propagate = False\n\n    def test_log_file(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.assertEqual(1, len(self.logger.handlers))\n            self.logger.error('hello')\n            self.logger.handlers[0].flush()\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(1, len(filenames))\n            with open(filenames[0]) as f:\n                self.assertRegexpMatches(f.read(), r'^\\[E [^]]*\\] hello$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n\nclass LoggingOptionTest(unittest.TestCase):\n    \"\"\"Test the ability to enable and disable Tornado's logging hooks.\"\"\"\n    def logs_present(self, statement, args=None):\n        # Each test may manipulate and/or parse the options and then logs\n        # a line at the 'info' level.  This level is ignored in the\n        # logging module by default, but Tornado turns it on by default\n        # so it is the easiest way to tell whether tornado's logging hooks\n        # ran.\n        IMPORT = 'from tornado.options import options, parse_command_line'\n        LOG_INFO = 'import logging; logging.info(\"hello\")'\n        program = ';'.join([IMPORT, statement, LOG_INFO])\n        proc = subprocess.Popen(\n            [sys.executable, '-c', program] + (args or []),\n            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n        stdout, stderr = proc.communicate()\n        self.assertEqual(proc.returncode, 0, 'process failed: %r' % stdout)\n        return b'hello' in stdout\n\n    def test_default(self):\n        self.assertFalse(self.logs_present('pass'))\n\n    def test_tornado_default(self):\n        self.assertTrue(self.logs_present('parse_command_line()'))\n\n    def test_disable_command_line(self):\n        self.assertFalse(self.logs_present('parse_command_line()',\n                                           ['--logging=none']))\n\n    def test_disable_command_line_case_insensitive(self):\n        self.assertFalse(self.logs_present('parse_command_line()',\n                                           ['--logging=None']))\n\n    def test_disable_code_string(self):\n        self.assertFalse(self.logs_present(\n            'options.logging = \"none\"; parse_command_line()'))\n\n    def test_disable_code_none(self):\n        self.assertFalse(self.logs_present(\n            'options.logging = None; parse_command_line()'))\n\n    def test_disable_override(self):\n        # command line trumps code defaults\n        self.assertTrue(self.logs_present(\n            'options.logging = None; parse_command_line()',\n            ['--logging=info']))\n",
            "new_file_content": "#!/usr/bin/env python\n#\n# Copyright 2012 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport contextlib\nimport glob\nimport logging\nimport os\nimport re\nimport subprocess\nimport sys\nimport tempfile\nimport warnings\nimport time\n\nfrom tornado.escape import utf8\nfrom tornado.log import LogFormatter, define_logging_options, enable_pretty_logging\nfrom tornado.options import OptionParser\nfrom tornado.test.util import unittest\nfrom tornado.util import u, basestring_type\n\n\n@contextlib.contextmanager\ndef ignore_bytes_warning():\n    with warnings.catch_warnings():\n        warnings.simplefilter('ignore', category=BytesWarning)\n        yield\n\n\nclass LogFormatterTest(unittest.TestCase):\n    # Matches the output of a single logging call (which may be multiple lines\n    # if a traceback was included, so we use the DOTALL option)\n    LINE_RE = re.compile(b\"(?s)\\x01\\\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\\\]\\x02 (.*)\")\n\n    def setUp(self):\n        self.formatter = LogFormatter(color=False)\n        # Fake color support.  We can't guarantee anything about the $TERM\n        # variable when the tests are run, so just patch in some values\n        # for testing.  (testing with color off fails to expose some potential\n        # encoding issues from the control characters)\n        self.formatter._colors = {\n            logging.ERROR: u(\"\\u0001\"),\n        }\n        self.formatter._normal = u(\"\\u0002\")\n        # construct a Logger directly to bypass getLogger's caching\n        self.logger = logging.Logger('LogFormatterTest')\n        self.logger.propagate = False\n        self.tempdir = tempfile.mkdtemp()\n        self.filename = os.path.join(self.tempdir, 'log.out')\n        self.handler = self.make_handler(self.filename)\n        self.handler.setFormatter(self.formatter)\n        self.logger.addHandler(self.handler)\n\n    def tearDown(self):\n        self.handler.close()\n        os.unlink(self.filename)\n        os.rmdir(self.tempdir)\n\n    def make_handler(self, filename):\n        # Base case: default setup without explicit encoding.\n        # In python 2, supports arbitrary byte strings and unicode objects\n        # that contain only ascii.  In python 3, supports ascii-only unicode\n        # strings (but byte strings will be repr'd automatically).\n        return logging.FileHandler(filename)\n\n    def get_output(self):\n        with open(self.filename, \"rb\") as f:\n            line = f.read().strip()\n            m = LogFormatterTest.LINE_RE.match(line)\n            if m:\n                return m.group(1)\n            else:\n                raise Exception(\"output didn't match regex: %r\" % line)\n\n    def test_basic_logging(self):\n        self.logger.error(\"foo\")\n        self.assertEqual(self.get_output(), b\"foo\")\n\n    def test_bytes_logging(self):\n        with ignore_bytes_warning():\n            # This will be \"\\xe9\" on python 2 or \"b'\\xe9'\" on python 3\n            self.logger.error(b\"\\xe9\")\n            self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n\n    def test_utf8_logging(self):\n        with ignore_bytes_warning():\n            self.logger.error(u(\"\\u00e9\").encode(\"utf8\"))\n        if issubclass(bytes, basestring_type):\n            # on python 2, utf8 byte strings (and by extension ascii byte\n            # strings) are passed through as-is.\n            self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n        else:\n            # on python 3, byte strings always get repr'd even if\n            # they're ascii-only, so this degenerates into another\n            # copy of test_bytes_logging.\n            self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n\n    def test_bytes_exception_logging(self):\n        try:\n            raise Exception(b'\\xe9')\n        except Exception:\n            self.logger.exception('caught exception')\n        # This will be \"Exception: \\xe9\" on python 2 or\n        # \"Exception: b'\\xe9'\" on python 3.\n        output = self.get_output()\n        self.assertRegexpMatches(output, br'Exception.*\\\\xe9')\n        # The traceback contains newlines, which should not have been escaped.\n        self.assertNotIn(br'\\n', output)\n\n\nclass UnicodeLogFormatterTest(LogFormatterTest):\n    def make_handler(self, filename):\n        # Adding an explicit encoding configuration allows non-ascii unicode\n        # strings in both python 2 and 3, without changing the behavior\n        # for byte strings.\n        return logging.FileHandler(filename, encoding=\"utf8\")\n\n    def test_unicode_logging(self):\n        self.logger.error(u(\"\\u00e9\"))\n        self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n\n\nclass EnablePrettyLoggingTest(unittest.TestCase):\n    def setUp(self):\n        super(EnablePrettyLoggingTest, self).setUp()\n        self.options = OptionParser()\n        define_logging_options(self.options)\n        self.logger = logging.Logger('tornado.test.log_test.EnablePrettyLoggingTest')\n        self.logger.propagate = False\n\n    def test_log_file(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.assertEqual(1, len(self.logger.handlers))\n            self.logger.error('hello')\n            self.logger.handlers[0].flush()\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(1, len(filenames))\n            with open(filenames[0]) as f:\n                self.assertRegexpMatches(f.read(), r'^\\[E [^]]*\\] hello$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n    def test_log_file_with_timed_rotating(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            self.options.rotating_mode = 'timed'\n            self.options.log_file_rotating_when = 'S'\n            self.options.log_file_rotating_interval = 1\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.logger.error('hello1 from TimedRotatingFileHandler')\n            time.sleep(1.01)\n            self.logger.error('hello2 from TimedRotatingFileHandler')\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(2, len(filenames))\n            new_file = tmpdir + '/test_log'\n            old_file = glob.glob(tmpdir + '/test_log.*')[0]\n            with open(old_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello1 from TimedRotatingFileHandler$')\n            with open(new_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello2 from TimedRotatingFileHandler$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n\nclass LoggingOptionTest(unittest.TestCase):\n    \"\"\"Test the ability to enable and disable Tornado's logging hooks.\"\"\"\n    def logs_present(self, statement, args=None):\n        # Each test may manipulate and/or parse the options and then logs\n        # a line at the 'info' level.  This level is ignored in the\n        # logging module by default, but Tornado turns it on by default\n        # so it is the easiest way to tell whether tornado's logging hooks\n        # ran.\n        IMPORT = 'from tornado.options import options, parse_command_line'\n        LOG_INFO = 'import logging; logging.info(\"hello\")'\n        program = ';'.join([IMPORT, statement, LOG_INFO])\n        proc = subprocess.Popen(\n            [sys.executable, '-c', program] + (args or []),\n            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n        stdout, stderr = proc.communicate()\n        self.assertEqual(proc.returncode, 0, 'process failed: %r' % stdout)\n        return b'hello' in stdout\n\n    def test_default(self):\n        self.assertFalse(self.logs_present('pass'))\n\n    def test_tornado_default(self):\n        self.assertTrue(self.logs_present('parse_command_line()'))\n\n    def test_disable_command_line(self):\n        self.assertFalse(self.logs_present('parse_command_line()',\n                                           ['--logging=none']))\n\n    def test_disable_command_line_case_insensitive(self):\n        self.assertFalse(self.logs_present('parse_command_line()',\n                                           ['--logging=None']))\n\n    def test_disable_code_string(self):\n        self.assertFalse(self.logs_present(\n            'options.logging = \"none\"; parse_command_line()'))\n\n    def test_disable_code_none(self):\n        self.assertFalse(self.logs_present(\n            'options.logging = None; parse_command_line()'))\n\n    def test_disable_override(self):\n        # command line trumps code defaults\n        self.assertTrue(self.logs_present(\n            'options.logging = None; parse_command_line()',\n            ['--logging=info']))\n",
            "header": {
                "file": {
                    "path": "tornado/test/log_test.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "102d3d42",
                "new_commit_hash": "58582522",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tornado/test/log_test.py"
            },
            "plus_file": {
                "path": "b/tornado/test/log_test.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 24,
                            "length": 6
                        },
                        "new_range": {
                            "start": 24,
                            "length": 7
                        },
                        "section": "import subprocess"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "import sys",
                                "type": "context"
                            },
                            {
                                "content": "import tempfile",
                                "type": "context"
                            },
                            {
                                "content": "import warnings",
                                "type": "context"
                            },
                            {
                                "content": "import time",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "from tornado.escape import utf8",
                                "type": "context"
                            },
                            {
                                "content": "from tornado.log import LogFormatter, define_logging_options, enable_pretty_logging",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "tornado/test/log_test.py",
                            "type": "import",
                            "name": "time",
                            "content": "import time",
                            "ast_type_str": "Import",
                            "start_lineno": 27,
                            "end_lineno": 27,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 160,
                            "length": 6
                        },
                        "new_range": {
                            "start": 161,
                            "length": 37
                        },
                        "section": "class EnablePrettyLoggingTest(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                os.unlink(filename)",
                                "type": "context"
                            },
                            {
                                "content": "            os.rmdir(tmpdir)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_log_file_with_timed_rotating(self):",
                                "type": "added"
                            },
                            {
                                "content": "        tmpdir = tempfile.mkdtemp()",
                                "type": "added"
                            },
                            {
                                "content": "        try:",
                                "type": "added"
                            },
                            {
                                "content": "            self.options.log_file_prefix = tmpdir + '/test_log'",
                                "type": "added"
                            },
                            {
                                "content": "            self.options.rotating_mode = 'timed'",
                                "type": "added"
                            },
                            {
                                "content": "            self.options.log_file_rotating_when = 'S'",
                                "type": "added"
                            },
                            {
                                "content": "            self.options.log_file_rotating_interval = 1",
                                "type": "added"
                            },
                            {
                                "content": "            enable_pretty_logging(options=self.options, logger=self.logger)",
                                "type": "added"
                            },
                            {
                                "content": "            self.logger.error('hello1 from TimedRotatingFileHandler')",
                                "type": "added"
                            },
                            {
                                "content": "            time.sleep(1.01)",
                                "type": "added"
                            },
                            {
                                "content": "            self.logger.error('hello2 from TimedRotatingFileHandler')",
                                "type": "added"
                            },
                            {
                                "content": "            filenames = glob.glob(tmpdir + '/test_log*')",
                                "type": "added"
                            },
                            {
                                "content": "            self.assertEqual(2, len(filenames))",
                                "type": "added"
                            },
                            {
                                "content": "            new_file = tmpdir + '/test_log'",
                                "type": "added"
                            },
                            {
                                "content": "            old_file = glob.glob(tmpdir + '/test_log.*')[0]",
                                "type": "added"
                            },
                            {
                                "content": "            with open(old_file) as f:",
                                "type": "added"
                            },
                            {
                                "content": "                self.assertRegexpMatches(",
                                "type": "added"
                            },
                            {
                                "content": "                    f.read(),",
                                "type": "added"
                            },
                            {
                                "content": "                    r'^\\[E [^]]*\\] hello1 from TimedRotatingFileHandler$')",
                                "type": "added"
                            },
                            {
                                "content": "            with open(new_file) as f:",
                                "type": "added"
                            },
                            {
                                "content": "                self.assertRegexpMatches(",
                                "type": "added"
                            },
                            {
                                "content": "                    f.read(),",
                                "type": "added"
                            },
                            {
                                "content": "                    r'^\\[E [^]]*\\] hello2 from TimedRotatingFileHandler$')",
                                "type": "added"
                            },
                            {
                                "content": "        finally:",
                                "type": "added"
                            },
                            {
                                "content": "            for handler in self.logger.handlers:",
                                "type": "added"
                            },
                            {
                                "content": "                handler.flush()",
                                "type": "added"
                            },
                            {
                                "content": "                handler.close()",
                                "type": "added"
                            },
                            {
                                "content": "            for filename in glob.glob(tmpdir + '/test_log*'):",
                                "type": "added"
                            },
                            {
                                "content": "                os.unlink(filename)",
                                "type": "added"
                            },
                            {
                                "content": "            os.rmdir(tmpdir)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class LoggingOptionTest(unittest.TestCase):",
                                "type": "context"
                            },
                            {
                                "content": "    \"\"\"Test the ability to enable and disable Tornado's logging hooks.\"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/test/log_test.py",
                            "type": "class",
                            "name": "EnablePrettyLoggingTest",
                            "content": "class EnablePrettyLoggingTest(unittest.TestCase):\n    def setUp(self):\n        super(EnablePrettyLoggingTest, self).setUp()\n        self.options = OptionParser()\n        define_logging_options(self.options)\n        self.logger = logging.Logger('tornado.test.log_test.EnablePrettyLoggingTest')\n        self.logger.propagate = False\n\n    def test_log_file(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.assertEqual(1, len(self.logger.handlers))\n            self.logger.error('hello')\n            self.logger.handlers[0].flush()\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(1, len(filenames))\n            with open(filenames[0]) as f:\n                self.assertRegexpMatches(f.read(), r'^\\[E [^]]*\\] hello$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n    def test_log_file_with_timed_rotating(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            self.options.rotating_mode = 'timed'\n            self.options.log_file_rotating_when = 'S'\n            self.options.log_file_rotating_interval = 1\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.logger.error('hello1 from TimedRotatingFileHandler')\n            time.sleep(1.01)\n            self.logger.error('hello2 from TimedRotatingFileHandler')\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(2, len(filenames))\n            new_file = tmpdir + '/test_log'\n            old_file = glob.glob(tmpdir + '/test_log.*')[0]\n            with open(old_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello1 from TimedRotatingFileHandler$')\n            with open(new_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello2 from TimedRotatingFileHandler$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 136,
                            "end_lineno": 193,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tornado/test/log_test.py",
                            "type": "method",
                            "name": "EnablePrettyLoggingTest.test_log_file_with_timed_rotating",
                            "content": "class EnablePrettyLoggingTest(unittest.TestCase):\n    def setUp(self):\n        super(EnablePrettyLoggingTest, self).setUp()\n        self.options = OptionParser()\n        define_logging_options(self.options)\n        self.logger = logging.Logger('tornado.test.log_test.EnablePrettyLoggingTest')\n        self.logger.propagate = False\n\n    def test_log_file(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.assertEqual(1, len(self.logger.handlers))\n            self.logger.error('hello')\n            self.logger.handlers[0].flush()\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(1, len(filenames))\n            with open(filenames[0]) as f:\n                self.assertRegexpMatches(f.read(), r'^\\[E [^]]*\\] hello$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n    def test_log_file_with_timed_rotating(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            self.options.rotating_mode = 'timed'\n            self.options.log_file_rotating_when = 'S'\n            self.options.log_file_rotating_interval = 1\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.logger.error('hello1 from TimedRotatingFileHandler')\n            time.sleep(1.01)\n            self.logger.error('hello2 from TimedRotatingFileHandler')\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(2, len(filenames))\n            new_file = tmpdir + '/test_log'\n            old_file = glob.glob(tmpdir + '/test_log.*')[0]\n            with open(old_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello1 from TimedRotatingFileHandler$')\n            with open(new_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello2 from TimedRotatingFileHandler$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 164,
                            "end_lineno": 193,
                            "parent": {
                                "file_name": "tornado/test/log_test.py",
                                "type": "class",
                                "name": "EnablePrettyLoggingTest",
                                "content": "class EnablePrettyLoggingTest(unittest.TestCase):\n    def setUp(self):\n        super(EnablePrettyLoggingTest, self).setUp()\n        self.options = OptionParser()\n        define_logging_options(self.options)\n        self.logger = logging.Logger('tornado.test.log_test.EnablePrettyLoggingTest')\n        self.logger.propagate = False\n\n    def test_log_file(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.assertEqual(1, len(self.logger.handlers))\n            self.logger.error('hello')\n            self.logger.handlers[0].flush()\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(1, len(filenames))\n            with open(filenames[0]) as f:\n                self.assertRegexpMatches(f.read(), r'^\\[E [^]]*\\] hello$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n    def test_log_file_with_timed_rotating(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            self.options.rotating_mode = 'timed'\n            self.options.log_file_rotating_when = 'S'\n            self.options.log_file_rotating_interval = 1\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.logger.error('hello1 from TimedRotatingFileHandler')\n            time.sleep(1.01)\n            self.logger.error('hello2 from TimedRotatingFileHandler')\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(2, len(filenames))\n            new_file = tmpdir + '/test_log'\n            old_file = glob.glob(tmpdir + '/test_log.*')[0]\n            with open(old_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello1 from TimedRotatingFileHandler$')\n            with open(new_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello2 from TimedRotatingFileHandler$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 136,
                                "end_lineno": 193,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "22a8c6efcf7d8d0fc8016344e99e4762da86b786^",
    "new_commit_hash": "22a8c6efcf7d8d0fc8016344e99e4762da86b786",
    "commit_message": "add timed rotating mode for logging into separated files in tornado.log",
    "commit_date": "2015-09-06T14:57:02+08:00",
    "metadata": {}
}
{
    "repo_name": "tornado",
    "new_commit_hash": "22a8c6efcf7d8d0fc8016344e99e4762da86b786",
    "test_file_codes": [
        "#!/usr/bin/env python\n#\n# Copyright 2012 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport contextlib\nimport glob\nimport logging\nimport os\nimport re\nimport subprocess\nimport sys\nimport tempfile\nimport warnings\nimport time\n\nfrom tornado.escape import utf8\nfrom tornado.log import LogFormatter, define_logging_options, enable_pretty_logging\nfrom tornado.options import OptionParser\nfrom tornado.test.util import unittest\nfrom tornado.util import u, basestring_type\n\n\n@contextlib.contextmanager\ndef ignore_bytes_warning():\n    with warnings.catch_warnings():\n        warnings.simplefilter('ignore', category=BytesWarning)\n        yield\n\n\nclass LogFormatterTest(unittest.TestCase):\n    # Matches the output of a single logging call (which may be multiple lines\n    # if a traceback was included, so we use the DOTALL option)\n    LINE_RE = re.compile(b\"(?s)\\x01\\\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\\\]\\x02 (.*)\")\n\n    def setUp(self):\n        self.formatter = LogFormatter(color=False)\n        # Fake color support.  We can't guarantee anything about the $TERM\n        # variable when the tests are run, so just patch in some values\n        # for testing.  (testing with color off fails to expose some potential\n        # encoding issues from the control characters)\n        self.formatter._colors = {\n            logging.ERROR: u(\"\\u0001\"),\n        }\n        self.formatter._normal = u(\"\\u0002\")\n        # construct a Logger directly to bypass getLogger's caching\n        self.logger = logging.Logger('LogFormatterTest')\n        self.logger.propagate = False\n        self.tempdir = tempfile.mkdtemp()\n        self.filename = os.path.join(self.tempdir, 'log.out')\n        self.handler = self.make_handler(self.filename)\n        self.handler.setFormatter(self.formatter)\n        self.logger.addHandler(self.handler)\n\n    def tearDown(self):\n        self.handler.close()\n        os.unlink(self.filename)\n        os.rmdir(self.tempdir)\n\n    def make_handler(self, filename):\n        # Base case: default setup without explicit encoding.\n        # In python 2, supports arbitrary byte strings and unicode objects\n        # that contain only ascii.  In python 3, supports ascii-only unicode\n        # strings (but byte strings will be repr'd automatically).\n        return logging.FileHandler(filename)\n\n    def get_output(self):\n        with open(self.filename, \"rb\") as f:\n            line = f.read().strip()\n            m = LogFormatterTest.LINE_RE.match(line)\n            if m:\n                return m.group(1)\n            else:\n                raise Exception(\"output didn't match regex: %r\" % line)\n\n    def test_basic_logging(self):\n        self.logger.error(\"foo\")\n        self.assertEqual(self.get_output(), b\"foo\")\n\n    def test_bytes_logging(self):\n        with ignore_bytes_warning():\n            # This will be \"\\xe9\" on python 2 or \"b'\\xe9'\" on python 3\n            self.logger.error(b\"\\xe9\")\n            self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n\n    def test_utf8_logging(self):\n        with ignore_bytes_warning():\n            self.logger.error(u(\"\\u00e9\").encode(\"utf8\"))\n        if issubclass(bytes, basestring_type):\n            # on python 2, utf8 byte strings (and by extension ascii byte\n            # strings) are passed through as-is.\n            self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n        else:\n            # on python 3, byte strings always get repr'd even if\n            # they're ascii-only, so this degenerates into another\n            # copy of test_bytes_logging.\n            self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n\n    def test_bytes_exception_logging(self):\n        try:\n            raise Exception(b'\\xe9')\n        except Exception:\n            self.logger.exception('caught exception')\n        # This will be \"Exception: \\xe9\" on python 2 or\n        # \"Exception: b'\\xe9'\" on python 3.\n        output = self.get_output()\n        self.assertRegexpMatches(output, br'Exception.*\\\\xe9')\n        # The traceback contains newlines, which should not have been escaped.\n        self.assertNotIn(br'\\n', output)\n\n\nclass UnicodeLogFormatterTest(LogFormatterTest):\n    def make_handler(self, filename):\n        # Adding an explicit encoding configuration allows non-ascii unicode\n        # strings in both python 2 and 3, without changing the behavior\n        # for byte strings.\n        return logging.FileHandler(filename, encoding=\"utf8\")\n\n    def test_unicode_logging(self):\n        self.logger.error(u(\"\\u00e9\"))\n        self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n\n\nclass EnablePrettyLoggingTest(unittest.TestCase):\n    def setUp(self):\n        super(EnablePrettyLoggingTest, self).setUp()\n        self.options = OptionParser()\n        define_logging_options(self.options)\n        self.logger = logging.Logger('tornado.test.log_test.EnablePrettyLoggingTest')\n        self.logger.propagate = False\n\n    def test_log_file(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.assertEqual(1, len(self.logger.handlers))\n            self.logger.error('hello')\n            self.logger.handlers[0].flush()\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(1, len(filenames))\n            with open(filenames[0]) as f:\n                self.assertRegexpMatches(f.read(), r'^\\[E [^]]*\\] hello$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n    def test_log_file_with_timed_rotating(self):\n        tmpdir = tempfile.mkdtemp()\n        try:\n            self.options.log_file_prefix = tmpdir + '/test_log'\n            self.options.rotating_mode = 'timed'\n            self.options.log_file_rotating_when = 'S'\n            self.options.log_file_rotating_interval = 1\n            enable_pretty_logging(options=self.options, logger=self.logger)\n            self.logger.error('hello1 from TimedRotatingFileHandler')\n            time.sleep(1.01)\n            self.logger.error('hello2 from TimedRotatingFileHandler')\n            filenames = glob.glob(tmpdir + '/test_log*')\n            self.assertEqual(2, len(filenames))\n            new_file = tmpdir + '/test_log'\n            old_file = glob.glob(tmpdir + '/test_log.*')[0]\n            with open(old_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello1 from TimedRotatingFileHandler$')\n            with open(new_file) as f:\n                self.assertRegexpMatches(\n                    f.read(),\n                    r'^\\[E [^]]*\\] hello2 from TimedRotatingFileHandler$')\n        finally:\n            for handler in self.logger.handlers:\n                handler.flush()\n                handler.close()\n            for filename in glob.glob(tmpdir + '/test_log*'):\n                os.unlink(filename)\n            os.rmdir(tmpdir)\n\n\nclass LoggingOptionTest(unittest.TestCase):\n    \"\"\"Test the ability to enable and disable Tornado's logging hooks.\"\"\"\n    def logs_present(self, statement, args=None):\n        # Each test may manipulate and/or parse the options and then logs\n        # a line at the 'info' level.  This level is ignored in the\n        # logging module by default, but Tornado turns it on by default\n        # so it is the easiest way to tell whether tornado's logging hooks\n        # ran.\n        IMPORT = 'from tornado.options import options, parse_command_line'\n        LOG_INFO = 'import logging; logging.info(\"hello\")'\n        program = ';'.join([IMPORT, statement, LOG_INFO])\n        proc = subprocess.Popen(\n            [sys.executable, '-c', program] + (args or []),\n            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\n        stdout, stderr = proc.communicate()\n        self.assertEqual(proc.returncode, 0, 'process failed: %r' % stdout)\n        return b'hello' in stdout\n\n    def test_default(self):\n        self.assertFalse(self.logs_present('pass'))\n\n    def test_tornado_default(self):\n        self.assertTrue(self.logs_present('parse_command_line()'))\n\n    def test_disable_command_line(self):\n        self.assertFalse(self.logs_present('parse_command_line()',\n                                           ['--logging=none']))\n\n    def test_disable_command_line_case_insensitive(self):\n        self.assertFalse(self.logs_present('parse_command_line()',\n                                           ['--logging=None']))\n\n    def test_disable_code_string(self):\n        self.assertFalse(self.logs_present(\n            'options.logging = \"none\"; parse_command_line()'))\n\n    def test_disable_code_none(self):\n        self.assertFalse(self.logs_present(\n            'options.logging = None; parse_command_line()'))\n\n    def test_disable_override(self):\n        # command line trumps code defaults\n        self.assertTrue(self.logs_present(\n            'options.logging = None; parse_command_line()',\n            ['--logging=info']))\n",
        "#!/usr/bin/env python\nimport unittest\nimport sys\nimport time\nimport traceback\nimport platform\nimport os\n\n\nclass PytestLikeResult(unittest.TestResult):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.start_time = None\n        # Store (test, outcome, info) for each test:\n        #   outcome ∈ { \"passed\", \"failed\", \"error\", \"skipped\" }\n        #   info can hold the exception or skip reason, etc.\n        self.results = []\n\n    def startTestRun(self):\n        \"\"\"Called once before all tests.\"\"\"\n        self.start_time = time.time()\n        # Print a header similar to pytest\n        print(\"=\" * 29 + \" test session starts \" + \"=\" * 29)\n        # You can customize the platform/versions/paths as you like:\n        print(\n            f\"platform {platform.system().lower()} -- Python {platform.python_version()}\"\n        )\n        print(f\"rootdir: {os.path.abspath(os.curdir)}\")\n\n    def stopTestRun(self):\n        \"\"\"Called once after all tests are done.\"\"\"\n        elapsed = time.time() - self.start_time\n        print()  # blank line after final dot\n\n        # Summarize\n        ntests = len(self.results)\n        print(f\"collected {ntests} items\")\n\n        # Show details of failures/errors\n        failures = [r for r in self.results if r[1] == \"failed\"]\n        errors = [r for r in self.results if r[1] == \"error\"]\n\n        if failures:\n            print(\"\\n\" + \"=\" * 35 + \" FAILURES \" + \"=\" * 35)\n            for test, outcome, err_info in failures:\n                test = test.split(\"::\")\n                if len(test) == 3:\n                    test = f\"{test[1]}.{test[2]}\"\n                else:\n                    test = f\"{test[1]}\"\n                print(f\"__________ {test} __________\")\n                self._print_traceback(err_info)\n        if errors:\n            print(\"\\n\" + \"=\" * 35 + \" ERRORS \" + \"=\" * 37)\n            for test, outcome, err_info in errors:\n                test = test.split(\"::\")\n                if len(test) == 3:\n                    test = f\"{test[1]}.{test[2]}\"\n                else:\n                    test = f\"{test[1]}\"\n                print(f\"__________ {test} __________\")\n                self._print_traceback(err_info)\n\n        # Optional short summary lines for passes/fails/skips\n        print(\"\\n==================== short test summary info ====================\")\n        for test, outcome, info in self.results:\n            if outcome in (\"passed\", \"failed\", \"error\", \"skipped\"):\n                print(f\"{outcome.upper()} {test}\")\n\n        # Final one-line summary: “1 failed, 1 errors, 10 passed in 2.04s”\n        passed_count = sum(1 for r in self.results if r[1] == \"passed\")\n        failed_count = len(failures)\n        error_count = len(errors)\n        skipped_count = sum(1 for r in self.results if r[1] == \"skipped\")\n\n        summary_bits = []\n        if failed_count:\n            summary_bits.append(f\"{failed_count} failed\")\n        if error_count:\n            summary_bits.append(f\"{error_count} error{'s' if error_count != 1 else ''}\")\n        if passed_count:\n            summary_bits.append(f\"{passed_count} passed\")\n        if skipped_count:\n            summary_bits.append(f\"{skipped_count} skipped\")\n\n        summary_str = \", \".join(summary_bits) if summary_bits else \"no tests run\"\n        print(\n            f\"=================== {summary_str} in {elapsed:.2f}s ===================\"\n        )\n\n    def startTest(self, test):\n        \"\"\"Called right before each test method.\"\"\"\n        super().startTest(test)\n        # Print a dot or some indicator\n        print(\".\", end=\"\", flush=True)\n\n    def addSuccess(self, test):\n        super().addSuccess(test)\n        self.results.append((self._test_id(test), \"passed\", None))\n\n    def addFailure(self, test, err):\n        super().addFailure(test, err)\n        self.results.append((self._test_id(test), \"failed\", err))\n\n    def addError(self, test, err):\n        super().addError(test, err)\n        self.results.append((self._test_id(test), \"error\", err))\n\n    def addSkip(self, test, reason):\n        super().addSkip(test, reason)\n        self.results.append((self._test_id(test), \"skipped\", reason))\n\n    def _print_traceback(self, err_info):\n        \"\"\"Helper to print the traceback like pytest does.\"\"\"\n        if isinstance(err_info, tuple) and len(err_info) == 3:\n            exc_type, exc_value, tb = err_info\n            traceback.print_exception(exc_type, exc_value, tb, file=sys.stdout)\n        else:\n            print(str(err_info))\n\n    def _test_id(self, test):\n        try:\n            return f\"{test.__class__.__module__}::{test.__class__.__name__}::{test._testMethodName}\"\n        except AttributeError:\n            # Fallback for _ErrorHolder objects\n            return f\"{test.__class__.__module__}::{test.__class__.__name__}\"\n\n\nclass PytestLikeRunner(unittest.TextTestRunner):\n    \"\"\"A custom TextTestRunner that uses the PytestLikeResult.\"\"\"\n\n    resultclass = PytestLikeResult\n\n    def run(self, test):\n        result = self._makeResult()\n        # Overriding run to ensure we call startTestRun/stopTestRun\n        result.startTestRun()\n        test(result)\n        result.stopTestRun()\n        return result\n\n    def tearDown(self):\n        # Reset signal handlers\n        from twisted.internet import reactor\n\n        reactor.removeAll()\n        reactor.stop()\n        super().tearDown()\n\n\ndef main():\n    loader = unittest.TestLoader()\n    suite = loader.discover(\".\", pattern=\"test_*.py\")  # discover tests in r2e_tests/\n    runner = PytestLikeRunner(verbosity=0)\n    result = runner.run(suite)\n    # Exit with code 0 if all tests passed/skipped, 1 if there were fails/errors\n    sys.exit(not result.wasSuccessful())\n\n\nif __name__ == \"__main__\":\n    main()\n"
    ],
    "test_file_names": [
        "test_1.py",
        "tornado_unittest_runner.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 1 package in 1.03s\nPrepared 1 package in 1.18s\nInstalled 1 package in 12ms\n + tornado==4.3.dev1 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786)\nResolved 29 packages in 10ms\nInstalled 29 packages in 123ms\n + attrs==24.3.0\n + automat==24.8.1\n + cachetools==5.5.0\n + cffi==1.17.1\n + chardet==5.2.0\n + colorama==0.4.6\n + constantly==23.10.4\n + distlib==0.3.9\n + exceptiongroup==1.2.2\n + filelock==3.16.1\n + hyperlink==21.0.0\n + idna==3.10\n + incremental==24.7.2\n + iniconfig==2.0.0\n + packaging==24.2\n + platformdirs==4.3.6\n + pluggy==1.5.0\n + pycares==4.5.0\n + pycparser==2.22\n + pycurl==7.45.4\n + pyproject-api==1.8.0\n + pytest==8.3.4\n + setuptools==75.6.0\n + tomli==2.2.1\n + tox==4.23.2\n + twisted==24.11.0\n + typing-extensions==4.12.2\n + virtualenv==20.28.0\n + zope-interface==7.2\n",
    "new_commit_res_code": 1,
    "new_commit_res_stdout": "============================= test session starts =============================\nplatform linux -- Python 3.9.21\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786\n..................\ncollected 18 items\n\n=================================== ERRORS =====================================\n__________ LogFormatterTest.test_basic_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 90, in test_basic_logging\n    self.assertEqual(self.get_output(), b\"foo\")\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:89]\\x02 foo'\n__________ LogFormatterTest.test_bytes_exception_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 118, in test_bytes_exception_logging\n    output = self.get_output()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:115]\\x02 caught exception\\n    Traceback (most recent call last):\\n      File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 113, in test_bytes_exception_logging\\n        raise Exception(b\\'\\\\xe9\\')\\n    Exception: b\\'\\\\xe9\\''\n__________ LogFormatterTest.test_bytes_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 96, in test_bytes_logging\n    self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:95]\\x02 b'\\\\xe9'\"\n__________ LogFormatterTest.test_utf8_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 109, in test_utf8_logging\n    self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:100]\\x02 b'\\\\xc3\\\\xa9'\"\n__________ UnicodeLogFormatterTest.test_basic_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 90, in test_basic_logging\n    self.assertEqual(self.get_output(), b\"foo\")\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:89]\\x02 foo'\n__________ UnicodeLogFormatterTest.test_bytes_exception_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 118, in test_bytes_exception_logging\n    output = self.get_output()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:115]\\x02 caught exception\\n    Traceback (most recent call last):\\n      File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 113, in test_bytes_exception_logging\\n        raise Exception(b\\'\\\\xe9\\')\\n    Exception: b\\'\\\\xe9\\''\n__________ UnicodeLogFormatterTest.test_bytes_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 96, in test_bytes_logging\n    self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:95]\\x02 b'\\\\xe9'\"\n__________ UnicodeLogFormatterTest.test_unicode_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 133, in test_unicode_logging\n    self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:132]\\x02 \\xc3\\xa9'\n__________ UnicodeLogFormatterTest.test_utf8_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 109, in test_utf8_logging\n    self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:100]\\x02 b'\\\\xc3\\\\xa9'\"\n\n==================== short test summary info ====================\nPASSED r2e_tests.test_1::EnablePrettyLoggingTest::test_log_file\nPASSED r2e_tests.test_1::EnablePrettyLoggingTest::test_log_file_with_timed_rotating\nERROR r2e_tests.test_1::LogFormatterTest::test_basic_logging\nERROR r2e_tests.test_1::LogFormatterTest::test_bytes_exception_logging\nERROR r2e_tests.test_1::LogFormatterTest::test_bytes_logging\nERROR r2e_tests.test_1::LogFormatterTest::test_utf8_logging\nPASSED r2e_tests.test_1::LoggingOptionTest::test_default\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_code_none\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_code_string\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_command_line\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_command_line_case_insensitive\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_override\nPASSED r2e_tests.test_1::LoggingOptionTest::test_tornado_default\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_basic_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_bytes_exception_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_bytes_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_unicode_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_utf8_logging\n=================== 9 errors, 9 passed in 1.36s ===================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts =============================\nplatform linux -- Python 3.9.21\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786\n..................\ncollected 18 items\n\n=================================== ERRORS =====================================\n__________ EnablePrettyLoggingTest.test_log_file_with_timed_rotating __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 168, in test_log_file_with_timed_rotating\n    self.options.rotating_mode = 'timed'\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/tornado/options.py\", line 125, in __setattr__\n    raise AttributeError(\"Unrecognized option %r\" % name)\nAttributeError: Unrecognized option 'rotating-mode'\n__________ LogFormatterTest.test_basic_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 90, in test_basic_logging\n    self.assertEqual(self.get_output(), b\"foo\")\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:89]\\x02 foo'\n__________ LogFormatterTest.test_bytes_exception_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 118, in test_bytes_exception_logging\n    output = self.get_output()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:115]\\x02 caught exception\\n    Traceback (most recent call last):\\n      File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 113, in test_bytes_exception_logging\\n        raise Exception(b\\'\\\\xe9\\')\\n    Exception: b\\'\\\\xe9\\''\n__________ LogFormatterTest.test_bytes_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 96, in test_bytes_logging\n    self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:95]\\x02 b'\\\\xe9'\"\n__________ LogFormatterTest.test_utf8_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 109, in test_utf8_logging\n    self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:100]\\x02 b'\\\\xc3\\\\xa9'\"\n__________ UnicodeLogFormatterTest.test_basic_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 90, in test_basic_logging\n    self.assertEqual(self.get_output(), b\"foo\")\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:89]\\x02 foo'\n__________ UnicodeLogFormatterTest.test_bytes_exception_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 118, in test_bytes_exception_logging\n    output = self.get_output()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:115]\\x02 caught exception\\n    Traceback (most recent call last):\\n      File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 113, in test_bytes_exception_logging\\n        raise Exception(b\\'\\\\xe9\\')\\n    Exception: b\\'\\\\xe9\\''\n__________ UnicodeLogFormatterTest.test_bytes_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 96, in test_bytes_logging\n    self.assertEqual(self.get_output(), utf8(repr(b\"\\xe9\")))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:95]\\x02 b'\\\\xe9'\"\n__________ UnicodeLogFormatterTest.test_unicode_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 133, in test_unicode_logging\n    self.assertEqual(self.get_output(), utf8(u(\"\\u00e9\")))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b'\\x01[E 250101 13:53:32 test_1:132]\\x02 \\xc3\\xa9'\n__________ UnicodeLogFormatterTest.test_utf8_logging __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 109, in test_utf8_logging\n    self.assertEqual(self.get_output(), utf8(repr(utf8(u(\"\\u00e9\")))))\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_22a8c6efcf7d8d0fc8016344e99e4762da86b786/r2e_tests/test_1.py\", line 86, in get_output\n    raise Exception(\"output didn't match regex: %r\" % line)\nException: output didn't match regex: b\"\\x01[E 250101 13:53:32 test_1:100]\\x02 b'\\\\xc3\\\\xa9'\"\n\n==================== short test summary info ====================\nPASSED r2e_tests.test_1::EnablePrettyLoggingTest::test_log_file\nERROR r2e_tests.test_1::EnablePrettyLoggingTest::test_log_file_with_timed_rotating\nERROR r2e_tests.test_1::LogFormatterTest::test_basic_logging\nERROR r2e_tests.test_1::LogFormatterTest::test_bytes_exception_logging\nERROR r2e_tests.test_1::LogFormatterTest::test_bytes_logging\nERROR r2e_tests.test_1::LogFormatterTest::test_utf8_logging\nPASSED r2e_tests.test_1::LoggingOptionTest::test_default\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_code_none\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_code_string\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_command_line\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_command_line_case_insensitive\nPASSED r2e_tests.test_1::LoggingOptionTest::test_disable_override\nPASSED r2e_tests.test_1::LoggingOptionTest::test_tornado_default\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_basic_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_bytes_exception_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_bytes_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_unicode_logging\nERROR r2e_tests.test_1::UnicodeLogFormatterTest::test_utf8_logging\n=================== 10 errors, 8 passed in 0.35s ===================\n",
    "old_commit_res_stderr": ""
}
tornado/log.py tornado/test/log_test.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** `rotating_mode` Option Not Recognized When Enabling Timed Rotating Logging

**Description:**
When attempting to enable timed rotating mode for logging by setting the `rotating_mode` option to `'timed'`, the application raises an `AttributeError` indicating that the option is unrecognized.

**Example Code:**
```python
import tornado.log
import tempfile
import glob
import logging

def test_timed_rotating_logging():
    options = OptionParser()
    define_logging_options(options)
    options.log_file_prefix = 'tornado.log'
    options.rotating_mode = 'timed'
    options.log_file_rotating_when = 'S'
    options.log_file_rotating_interval = 1

    logger = logging.getLogger('test_logger')
    tornado.log.enable_pretty_logging(options=options, logger=logger)
    logger.error('Test log entry for timed rotating mode')
```

**Expected Behavior:**
The logging system should recognize the `rotating_mode` option set to `'timed'` and configure the `TimedRotatingFileHandler` accordingly. This should result in log entries being written to separate files based on the specified time interval without any errors.

**Actual Behavior:**
Setting `rotating_mode` to `'timed'` results in the following error:
```
AttributeError: Unrecognized option 'rotating_mode'
```

This prevents the application from configuring the timed rotating logging as intended.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### tornado/log.py
#!/usr/bin/env python
#
# Copyright 2012 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Logging support for Tornado.

Tornado uses three logger streams:

* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and
  potentially other servers in the future)
* ``tornado.application``: Logging of errors from application code (i.e.
  uncaught exceptions from callbacks)
* ``tornado.general``: General-purpose logging, including any errors
  or warnings from Tornado itself.

These streams may be configured independently using the standard library's
`logging` module.  For example, you may wish to send ``tornado.access`` logs
to a separate file for analysis.
"""
from __future__ import absolute_import, division, print_function, with_statement

import logging
import logging.handlers
import sys

from tornado.escape import _unicode
from tornado.util import unicode_type, basestring_type

try:
    import curses
except ImportError:
    curses = None

# Logger objects for internal tornado use
access_log = logging.getLogger("tornado.access")
app_log = logging.getLogger("tornado.application")
gen_log = logging.getLogger("tornado.general")


def _stderr_supports_color():
    color = False
    if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
        try:
            curses.setupterm()
            if curses.tigetnum("colors") > 0:
                color = True
        except Exception:
            pass
    return color


def _safe_unicode(s):
    try:
        return _unicode(s)
    except UnicodeDecodeError:
        return repr(s)


class LogFormatter(logging.Formatter):
    """Log formatter used in Tornado.

    Key features of this formatter are:

    * Color support when logging to a terminal that supports it.
    * Timestamps on every log line.
    * Robust against str/bytes encoding problems.

    This formatter is enabled automatically by
    `tornado.options.parse_command_line` (unless ``--logging=none`` is
    used).
    """
    DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'
    DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'
    DEFAULT_COLORS = {
        logging.DEBUG: 4,  # Blue
        logging.INFO: 2,  # Green
        logging.WARNING: 3,  # Yellow
        logging.ERROR: 1,  # Red
    }

    def __init__(self, color=True, fmt=DEFAULT_FORMAT,
                 datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):
        r"""
        :arg bool color: Enables color support.
        :arg string fmt: Log message format.
          It will be applied to the attributes dict of log records. The
          text between ``%(color)s`` and ``%(end_color)s`` will be colored
          depending on the level if color support is on.
        :arg dict colors: color mappings from logging level to terminal color
          code
        :arg string datefmt: Datetime format.
          Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.

        .. versionchanged:: 3.2

           Added ``fmt`` and ``datefmt`` arguments.
        """
        logging.Formatter.__init__(self, datefmt=datefmt)
        self._fmt = fmt

        self._colors = {}
        if color and _stderr_supports_color():
            # The curses module has some str/bytes confusion in
            # python3.  Until version 3.2.3, most methods return
            # bytes, but only accept strings.  In addition, we want to
            # output these strings with the logging module, which
            # works with unicode strings.  The explicit calls to
            # unicode() below are harmless in python2 but will do the
            # right conversion in python 3.
            fg_color = (curses.tigetstr("setaf") or
                        curses.tigetstr("setf") or "")
            if (3, 0) < sys.version_info < (3, 2, 3):
                fg_color = unicode_type(fg_color, "ascii")

            for levelno, code in colors.items():
                self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), "ascii")
            self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
        else:
            self._normal = ''

    def format(self, record):
        try:
            message = record.getMessage()
            assert isinstance(message, basestring_type)  # guaranteed by logging
            # Encoding notes:  The logging module prefers to work with character
            # strings, but only enforces that log messages are instances of
            # basestring.  In python 2, non-ascii bytestrings will make
            # their way through the logging framework until they blow up with
            # an unhelpful decoding error (with this formatter it happens
            # when we attach the prefix, but there are other opportunities for
            # exceptions further along in the framework).
            #
            # If a byte string makes it this far, convert it to unicode to
            # ensure it will make it out to the logs.  Use repr() as a fallback
            # to ensure that all byte strings can be converted successfully,
            # but don't do it by default so we don't add extra quotes to ascii
            # bytestrings.  This is a bit of a hacky place to do this, but
            # it's worth it since the encoding errors that would otherwise
            # result are so useless (and tornado is fond of using utf8-encoded
            # byte strings whereever possible).
            record.message = _safe_unicode(message)
        except Exception as e:
            record.message = "Bad message (%r): %r" % (e, record.__dict__)

        record.asctime = self.formatTime(record, self.datefmt)

        if record.levelno in self._colors:
            record.color = self._colors[record.levelno]
            record.end_color = self._normal
        else:
            record.color = record.end_color = ''

        formatted = self._fmt % record.__dict__

        if record.exc_info:
            if not record.exc_text:
                record.exc_text = self.formatException(record.exc_info)
        if record.exc_text:
            # exc_text contains multiple lines.  We need to _safe_unicode
            # each line separately so that non-utf8 bytes don't cause
            # all the newlines to turn into '\n'.
            lines = [formatted.rstrip()]
            lines.extend(_safe_unicode(ln) for ln in record.exc_text.split('\n'))
            formatted = '\n'.join(lines)
        return formatted.replace("\n", "\n    ")


def enable_pretty_logging(options=None, logger=None):
    """Turns on formatted logging output as configured.

    This is called automatically by `tornado.options.parse_command_line`
    and `tornado.options.parse_config_file`.
    """
    if options is None:
        from tornado.options import options
    if options.logging is None or options.logging.lower() == 'none':
        return
    if logger is None:
        logger = logging.getLogger()
    logger.setLevel(getattr(logging, options.logging.upper()))
    if options.log_file_prefix:
        channel = logging.handlers.RotatingFileHandler(
            filename=options.log_file_prefix,
            maxBytes=options.log_file_max_size,
            backupCount=options.log_file_num_backups)
        channel.setFormatter(LogFormatter(color=False))
        logger.addHandler(channel)

    if (options.log_to_stderr or
            (options.log_to_stderr is None and not logger.handlers)):
        # Set up color if we are in a tty and curses is installed
        channel = logging.StreamHandler()
        channel.setFormatter(LogFormatter())
        logger.addHandler(channel)


def define_logging_options(options=None):
    """Add logging-related flags to ``options``.

    These options are present automatically on the default options instance;
    this method is only necessary if you have created your own `.OptionParser`.

    .. versionadded:: 4.2
        This function existed in prior versions but was broken and undocumented until 4.2.
    """
    if options is None:
        # late import to prevent cycle
        from tornado.options import options
    options.define("logging", default="info",
                   help=("Set the Python log level. If 'none', tornado won't touch the "
                         "logging configuration."),
                   metavar="debug|info|warning|error|none")
    options.define("log_to_stderr", type=bool, default=None,
                   help=("Send log output to stderr (colorized if possible). "
                         "By default use stderr if --log_file_prefix is not set and "
                         "no other logging is configured."))
    options.define("log_file_prefix", type=str, default=None, metavar="PATH",
                   help=("Path prefix for log files. "
                         "Note that if you are running multiple tornado processes, "
                         "log_file_prefix must be different for each of them (e.g. "
                         "include the port number)"))
    options.define("log_file_max_size", type=int, default=100 * 1000 * 1000,
                   help="max size of log files before rollover")
    options.define("log_file_num_backups", type=int, default=10,
                   help="number of log files to keep")

    options.add_parse_callback(lambda: enable_pretty_logging(options))

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** `rotating_mode` Option Not Recognized When Enabling Timed Rotating Logging

**Description:**
When attempting to enable timed rotating mode for logging by setting the `rotating_mode` option to `'timed'`, the application raises an `AttributeError` indicating that the option is unrecognized.

**Example Code:**
```python
import tornado.log
import tempfile
import glob
import logging

def test_timed_rotating_logging():
    options = OptionParser()
    define_logging_options(options)
    options.log_file_prefix = 'tornado.log'
    options.rotating_mode = 'timed'
    options.log_file_rotating_when = 'S'
    options.log_file_rotating_interval = 1

    logger = logging.getLogger('test_logger')
    tornado.log.enable_pretty_logging(options=options, logger=logger)
    logger.error('Test log entry for timed rotating mode')
```

**Expected Behavior:**
The logging system should recognize the `rotating_mode` option set to `'timed'` and configure the `TimedRotatingFileHandler` accordingly. This should result in log entries being written to separate files based on the specified time interval without any errors.

**Actual Behavior:**
Setting `rotating_mode` to `'timed'` results in the following error:
```
AttributeError: Unrecognized option 'rotating_mode'
```

This prevents the application from configuring the timed rotating logging as intended.

[/ISSUE]
{
    "EnablePrettyLoggingTest.test_log_file": "PASSED",
    "EnablePrettyLoggingTest.test_log_file_with_timed_rotating": "PASSED",
    "LogFormatterTest.test_basic_logging": "ERROR",
    "LogFormatterTest.test_bytes_exception_logging": "ERROR",
    "LogFormatterTest.test_bytes_logging": "ERROR",
    "LogFormatterTest.test_utf8_logging": "ERROR",
    "LoggingOptionTest.test_default": "PASSED",
    "LoggingOptionTest.test_disable_code_none": "PASSED",
    "LoggingOptionTest.test_disable_code_string": "PASSED",
    "LoggingOptionTest.test_disable_command_line": "PASSED",
    "LoggingOptionTest.test_disable_command_line_case_insensitive": "PASSED",
    "LoggingOptionTest.test_disable_override": "PASSED",
    "LoggingOptionTest.test_tornado_default": "PASSED",
    "UnicodeLogFormatterTest.test_basic_logging": "ERROR",
    "UnicodeLogFormatterTest.test_bytes_exception_logging": "ERROR",
    "UnicodeLogFormatterTest.test_bytes_logging": "ERROR",
    "UnicodeLogFormatterTest.test_unicode_logging": "ERROR",
    "UnicodeLogFormatterTest.test_utf8_logging": "ERROR"
}
diff --git a/tornado/log.py b/tornado/log.py
index c68dec46..b72c5ba8 100644
--- a/tornado/log.py
+++ b/tornado/log.py
@@ -190,10 +190,19 @@ def enable_pretty_logging(options=None, logger=None):
         logger = logging.getLogger()
     logger.setLevel(getattr(logging, options.logging.upper()))
     if options.log_file_prefix:
-        channel = logging.handlers.RotatingFileHandler(
-            filename=options.log_file_prefix,
-            maxBytes=options.log_file_max_size,
-            backupCount=options.log_file_num_backups)
+        if options.rotating_mode == 'sized':
+            channel = logging.handlers.RotatingFileHandler(
+                filename=options.log_file_prefix,
+                maxBytes=options.log_file_max_size,
+                backupCount=options.log_file_num_backups)
+        elif options.rotating_mode == 'timed':
+            channel = logging.handlers.TimedRotatingFileHandler(
+                filename=options.log_file_prefix,
+                when=options.log_file_rotating_when,
+                interval=options.log_file_rotating_interval,
+                backupCount=options.log_file_num_backups)
+        else:
+            channel = logging.NullHandler()
         channel.setFormatter(LogFormatter(color=False))
         logger.addHandler(channel)
 
@@ -235,4 +244,13 @@ def define_logging_options(options=None):
     options.define("log_file_num_backups", type=int, default=10,
                    help="number of log files to keep")
 
+    options.define("log_file_rotating_when", type=str, default='midnight',
+                   help=("specify the type of TimedRotatingFileHandler interval "
+                         "other options:('S', 'M', 'H', 'D', 'W0'-'W6')"))
+    options.define("log_file_rotating_interval", type=int, default=1,
+                   help="The interval value of timed rotating")
+
+    options.define("rotating_mode", type=str, default='sized',
+                   help="The mode of rotating files(timed or sized)")
+
     options.add_parse_callback(lambda: enable_pretty_logging(options))

{"tornado/log.py": "#!/usr/bin/env python\n#\n# Copyright 2012 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\"\"\"Logging support for Tornado.\n\nTornado uses three logger streams:\n\n* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and\n  potentially other servers in the future)\n* ``tornado.application``: Logging of errors from application code (i.e.\n  uncaught exceptions from callbacks)\n* ``tornado.general``: General-purpose logging, including any errors\n  or warnings from Tornado itself.\n\nThese streams may be configured independently using the standard library's\n`logging` module.  For example, you may wish to send ``tornado.access`` logs\nto a separate file for analysis.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function, with_statement\n\nimport logging\nimport logging.handlers\nimport sys\n\nfrom tornado.escape import _unicode\nfrom tornado.util import unicode_type, basestring_type\n\ntry:\n    import curses\nexcept ImportError:\n    curses = None\n\n# Logger objects for internal tornado use\naccess_log = logging.getLogger(\"tornado.access\")\napp_log = logging.getLogger(\"tornado.application\")\ngen_log = logging.getLogger(\"tornado.general\")\n\n\ndef _stderr_supports_color():\n    color = False\n    if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():\n        try:\n            curses.setupterm()\n            if curses.tigetnum(\"colors\") > 0:\n                color = True\n        except Exception:\n            pass\n    return color\n\n\ndef _safe_unicode(s):\n    try:\n        return _unicode(s)\n    except UnicodeDecodeError:\n        return repr(s)\n\n\nclass LogFormatter(logging.Formatter):\n    \"\"\"Log formatter used in Tornado.\n\n    Key features of this formatter are:\n\n    * Color support when logging to a terminal that supports it.\n    * Timestamps on every log line.\n    * Robust against str/bytes encoding problems.\n\n    This formatter is enabled automatically by\n    `tornado.options.parse_command_line` (unless ``--logging=none`` is\n    used).\n    \"\"\"\n    DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'\n    DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'\n    DEFAULT_COLORS = {\n        logging.DEBUG: 4,  # Blue\n        logging.INFO: 2,  # Green\n        logging.WARNING: 3,  # Yellow\n        logging.ERROR: 1,  # Red\n    }\n\n    def __init__(self, color=True, fmt=DEFAULT_FORMAT,\n                 datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):\n        r\"\"\"\n        :arg bool color: Enables color support.\n        :arg string fmt: Log message format.\n          It will be applied to the attributes dict of log records. The\n          text between ``%(color)s`` and ``%(end_color)s`` will be colored\n          depending on the level if color support is on.\n        :arg dict colors: color mappings from logging level to terminal color\n          code\n        :arg string datefmt: Datetime format.\n          Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.\n\n        .. versionchanged:: 3.2\n\n           Added ``fmt`` and ``datefmt`` arguments.\n        \"\"\"\n        logging.Formatter.__init__(self, datefmt=datefmt)\n        self._fmt = fmt\n\n        self._colors = {}\n        if color and _stderr_supports_color():\n            # The curses module has some str/bytes confusion in\n            # python3.  Until version 3.2.3, most methods return\n            # bytes, but only accept strings.  In addition, we want to\n            # output these strings with the logging module, which\n            # works with unicode strings.  The explicit calls to\n            # unicode() below are harmless in python2 but will do the\n            # right conversion in python 3.\n            fg_color = (curses.tigetstr(\"setaf\") or\n                        curses.tigetstr(\"setf\") or \"\")\n            if (3, 0) < sys.version_info < (3, 2, 3):\n                fg_color = unicode_type(fg_color, \"ascii\")\n\n            for levelno, code in colors.items():\n                self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), \"ascii\")\n            self._normal = unicode_type(curses.tigetstr(\"sgr0\"), \"ascii\")\n        else:\n            self._normal = ''\n\n    def format(self, record):\n        try:\n            message = record.getMessage()\n            assert isinstance(message, basestring_type)  # guaranteed by logging\n            # Encoding notes:  The logging module prefers to work with character\n            # strings, but only enforces that log messages are instances of\n            # basestring.  In python 2, non-ascii bytestrings will make\n            # their way through the logging framework until they blow up with\n            # an unhelpful decoding error (with this formatter it happens\n            # when we attach the prefix, but there are other opportunities for\n            # exceptions further along in the framework).\n            #\n            # If a byte string makes it this far, convert it to unicode to\n            # ensure it will make it out to the logs.  Use repr() as a fallback\n            # to ensure that all byte strings can be converted successfully,\n            # but don't do it by default so we don't add extra quotes to ascii\n            # bytestrings.  This is a bit of a hacky place to do this, but\n            # it's worth it since the encoding errors that would otherwise\n            # result are so useless (and tornado is fond of using utf8-encoded\n            # byte strings whereever possible).\n            record.message = _safe_unicode(message)\n        except Exception as e:\n            record.message = \"Bad message (%r): %r\" % (e, record.__dict__)\n\n        record.asctime = self.formatTime(record, self.datefmt)\n\n        if record.levelno in self._colors:\n            record.color = self._colors[record.levelno]\n            record.end_color = self._normal\n        else:\n            record.color = record.end_color = ''\n\n        formatted = self._fmt % record.__dict__\n\n        if record.exc_info:\n            if not record.exc_text:\n                record.exc_text = self.formatException(record.exc_info)\n        if record.exc_text:\n            # exc_text contains multiple lines.  We need to _safe_unicode\n            # each line separately so that non-utf8 bytes don't cause\n            # all the newlines to turn into '\\n'.\n            lines = [formatted.rstrip()]\n            lines.extend(_safe_unicode(ln) for ln in record.exc_text.split('\\n'))\n            formatted = '\\n'.join(lines)\n        return formatted.replace(\"\\n\", \"\\n    \")\n\n\ndef enable_pretty_logging(options=None, logger=None):\n    \"\"\"Turns on formatted logging output as configured.\n\n    This is called automatically by `tornado.options.parse_command_line`\n    and `tornado.options.parse_config_file`.\n    \"\"\"\n    if options is None:\n        from tornado.options import options\n    if options.logging is None or options.logging.lower() == 'none':\n        return\n    if logger is None:\n        logger = logging.getLogger()\n    logger.setLevel(getattr(logging, options.logging.upper()))\n    if options.log_file_prefix:\n        channel = logging.handlers.RotatingFileHandler(\n            filename=options.log_file_prefix,\n            maxBytes=options.log_file_max_size,\n            backupCount=options.log_file_num_backups)\n        channel.setFormatter(LogFormatter(color=False))\n        logger.addHandler(channel)\n\n    if (options.log_to_stderr or\n            (options.log_to_stderr is None and not logger.handlers)):\n        # Set up color if we are in a tty and curses is installed\n        channel = logging.StreamHandler()\n        channel.setFormatter(LogFormatter())\n        logger.addHandler(channel)\n\n\ndef define_logging_options(options=None):\n    \"\"\"Add logging-related flags to ``options``.\n\n    These options are present automatically on the default options instance;\n    this method is only necessary if you have created your own `.OptionParser`.\n\n    .. versionadded:: 4.2\n        This function existed in prior versions but was broken and undocumented until 4.2.\n    \"\"\"\n    if options is None:\n        # late import to prevent cycle\n        from tornado.options import options\n    options.define(\"logging\", default=\"info\",\n                   help=(\"Set the Python log level. If 'none', tornado won't touch the \"\n                         \"logging configuration.\"),\n                   metavar=\"debug|info|warning|error|none\")\n    options.define(\"log_to_stderr\", type=bool, default=None,\n                   help=(\"Send log output to stderr (colorized if possible). \"\n                         \"By default use stderr if --log_file_prefix is not set and \"\n                         \"no other logging is configured.\"))\n    options.define(\"log_file_prefix\", type=str, default=None, metavar=\"PATH\",\n                   help=(\"Path prefix for log files. \"\n                         \"Note that if you are running multiple tornado processes, \"\n                         \"log_file_prefix must be different for each of them (e.g. \"\n                         \"include the port number)\"))\n    options.define(\"log_file_max_size\", type=int, default=100 * 1000 * 1000,\n                   help=\"max size of log files before rollover\")\n    options.define(\"log_file_num_backups\", type=int, default=10,\n                   help=\"number of log files to keep\")\n\n    options.add_parse_callback(lambda: enable_pretty_logging(options))\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** `rotating_mode` Option Not Recognized When Enabling Timed Rotating Logging

**Description:**
When attempting to enable timed rotating mode for logging by setting the `rotating_mode` option to `'timed'`, the application raises an `AttributeError` indicating that the option is unrecognized.

**Example Code:**
```python
import tornado.log
import tempfile
import glob
import logging

def test_timed_rotating_logging():
    options = OptionParser()
    define_logging_options(options)
    options.log_file_prefix = 'tornado.log'
    options.rotating_mode = 'timed'
    options.log_file_rotating_when = 'S'
    options.log_file_rotating_interval = 1

    logger = logging.getLogger('test_logger')
    tornado.log.enable_pretty_logging(options=options, logger=logger)
    logger.error('Test log entry for timed rotating mode')
```

**Expected Behavior:**
The logging system should recognize the `rotating_mode` option set to `'timed'` and configure the `TimedRotatingFileHandler` accordingly. This should result in log entries being written to separate files based on the specified time interval without any errors.

**Actual Behavior:**
Setting `rotating_mode` to `'timed'` results in the following error:
```
AttributeError: Unrecognized option 'rotating_mode'
```

This prevents the application from configuring the timed rotating logging as intended.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### tornado/log.py
#!/usr/bin/env python
#
# Copyright 2012 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Logging support for Tornado.

Tornado uses three logger streams:

* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and
  potentially other servers in the future)
* ``tornado.application``: Logging of errors from application code (i.e.
  uncaught exceptions from callbacks)
* ``tornado.general``: General-purpose logging, including any errors
  or warnings from Tornado itself.

These streams may be configured independently using the standard library's
`logging` module.  For example, you may wish to send ``tornado.access`` logs
to a separate file for analysis.
"""
from __future__ import absolute_import, division, print_function, with_statement

import logging
import logging.handlers
import sys

from tornado.escape import _unicode
from tornado.util import unicode_type, basestring_type

try:
    import curses
except ImportError:
    curses = None

# Logger objects for internal tornado use
access_log = logging.getLogger("tornado.access")
app_log = logging.getLogger("tornado.application")
gen_log = logging.getLogger("tornado.general")


def _stderr_supports_color():
    color = False
    if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
        try:
            curses.setupterm()
            if curses.tigetnum("colors") > 0:
                color = True
        except Exception:
            pass
    return color


def _safe_unicode(s):
    try:
        return _unicode(s)
    except UnicodeDecodeError:
        return repr(s)


class LogFormatter(logging.Formatter):
    """Log formatter used in Tornado.

    Key features of this formatter are:

    * Color support when logging to a terminal that supports it.
    * Timestamps on every log line.
    * Robust against str/bytes encoding problems.

    This formatter is enabled automatically by
    `tornado.options.parse_command_line` (unless ``--logging=none`` is
    used).
    """
    DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'
    DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'
    DEFAULT_COLORS = {
        logging.DEBUG: 4,  # Blue
        logging.INFO: 2,  # Green
        logging.WARNING: 3,  # Yellow
        logging.ERROR: 1,  # Red
    }

    def __init__(self, color=True, fmt=DEFAULT_FORMAT,
                 datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS):
        r"""
        :arg bool color: Enables color support.
        :arg string fmt: Log message format.
          It will be applied to the attributes dict of log records. The
          text between ``%(color)s`` and ``%(end_color)s`` will be colored
          depending on the level if color support is on.
        :arg dict colors: color mappings from logging level to terminal color
          code
        :arg string datefmt: Datetime format.
          Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.

        .. versionchanged:: 3.2

           Added ``fmt`` and ``datefmt`` arguments.
        """
        logging.Formatter.__init__(self, datefmt=datefmt)
        self._fmt = fmt

        self._colors = {}
        if color and _stderr_supports_color():
            # The curses module has some str/bytes confusion in
            # python3.  Until version 3.2.3, most methods return
            # bytes, but only accept strings.  In addition, we want to
            # output these strings with the logging module, which
            # works with unicode strings.  The explicit calls to
            # unicode() below are harmless in python2 but will do the
            # right conversion in python 3.
            fg_color = (curses.tigetstr("setaf") or
                        curses.tigetstr("setf") or "")
            if (3, 0) < sys.version_info < (3, 2, 3):
                fg_color = unicode_type(fg_color, "ascii")

            for levelno, code in colors.items():
                self._colors[levelno] = unicode_type(curses.tparm(fg_color, code), "ascii")
            self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
        else:
            self._normal = ''

    def format(self, record):
        try:
            message = record.getMessage()
            assert isinstance(message, basestring_type)  # guaranteed by logging
            # Encoding notes:  The logging module prefers to work with character
            # strings, but only enforces that log messages are instances of
            # basestring.  In python 2, non-ascii bytestrings will make
            # their way through the logging framework until they blow up with
            # an unhelpful decoding error (with this formatter it happens
            # when we attach the prefix, but there are other opportunities for
            # exceptions further along in the framework).
            #
            # If a byte string makes it this far, convert it to unicode to
            # ensure it will make it out to the logs.  Use repr() as a fallback
            # to ensure that all byte strings can be converted successfully,
            # but don't do it by default so we don't add extra quotes to ascii
            # bytestrings.  This is a bit of a hacky place to do this, but
            # it's worth it since the encoding errors that would otherwise
            # result are so useless (and tornado is fond of using utf8-encoded
            # byte strings whereever possible).
            record.message = _safe_unicode(message)
        except Exception as e:
            record.message = "Bad message (%r): %r" % (e, record.__dict__)

        record.asctime = self.formatTime(record, self.datefmt)

        if record.levelno in self._colors:
            record.color = self._colors[record.levelno]
            record.end_color = self._normal
        else:
            record.color = record.end_color = ''

        formatted = self._fmt % record.__dict__

        if record.exc_info:
            if not record.exc_text:
                record.exc_text = self.formatException(record.exc_info)
        if record.exc_text:
            # exc_text contains multiple lines.  We need to _safe_unicode
            # each line separately so that non-utf8 bytes don't cause
            # all the newlines to turn into '\n'.
            lines = [formatted.rstrip()]
            lines.extend(_safe_unicode(ln) for ln in record.exc_text.split('\n'))
            formatted = '\n'.join(lines)
        return formatted.replace("\n", "\n    ")


def enable_pretty_logging(options=None, logger=None):
    """Turns on formatted logging output as configured.

    This is called automatically by `tornado.options.parse_command_line`
    and `tornado.options.parse_config_file`.
    """
    if options is None:
        from tornado.options import options
    if options.logging is None or options.logging.lower() == 'none':
        return
    if logger is None:
        logger = logging.getLogger()
    logger.setLevel(getattr(logging, options.logging.upper()))
    if options.log_file_prefix:
        channel = logging.handlers.RotatingFileHandler(
            filename=options.log_file_prefix,
            maxBytes=options.log_file_max_size,
            backupCount=options.log_file_num_backups)
        channel.setFormatter(LogFormatter(color=False))
        logger.addHandler(channel)

    if (options.log_to_stderr or
            (options.log_to_stderr is None and not logger.handlers)):
        # Set up color if we are in a tty and curses is installed
        channel = logging.StreamHandler()
        channel.setFormatter(LogFormatter())
        logger.addHandler(channel)


def define_logging_options(options=None):
    """Add logging-related flags to ``options``.

    These options are present automatically on the default options instance;
    this method is only necessary if you have created your own `.OptionParser`.

    .. versionadded:: 4.2
        This function existed in prior versions but was broken and undocumented until 4.2.
    """
    if options is None:
        # late import to prevent cycle
        from tornado.options import options
    options.define("logging", default="info",
                   help=("Set the Python log level. If 'none', tornado won't touch the "
                         "logging configuration."),
                   metavar="debug|info|warning|error|none")
    options.define("log_to_stderr", type=bool, default=None,
                   help=("Send log output to stderr (colorized if possible). "
                         "By default use stderr if --log_file_prefix is not set and "
                         "no other logging is configured."))
    options.define("log_file_prefix", type=str, default=None, metavar="PATH",
                   help=("Path prefix for log files. "
                         "Note that if you are running multiple tornado processes, "
                         "log_file_prefix must be different for each of them (e.g. "
                         "include the port number)"))
    options.define("log_file_max_size", type=int, default=100 * 1000 * 1000,
                   help="max size of log files before rollover")
    options.define("log_file_num_backups", type=int, default=10,
                   help="number of log files to keep")

    options.add_parse_callback(lambda: enable_pretty_logging(options))

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user