We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
LogFormatter DEFAULT_COLORS needs a logging.CRITICAL entry
https://github.com/tornadoweb/tornado/blob/c447875a1058f4768c2995ddd9ebb0eaddd3f32e/tornado/log.py#L108-L113

Currently `ERROR` will log red, but `CRITICAL` will log in white.  Curses `COLOR_MAGENTA` (5) is probably the best option.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `tornado/log.py`
Content:
```
1 #
2 # Copyright 2012 Facebook
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15 """Logging support for Tornado.
16 
17 Tornado uses three logger streams:
18 
19 * ``tornado.access``: Per-request logging for Tornado's HTTP servers (and
20   potentially other servers in the future)
21 * ``tornado.application``: Logging of errors from application code (i.e.
22   uncaught exceptions from callbacks)
23 * ``tornado.general``: General-purpose logging, including any errors
24   or warnings from Tornado itself.
25 
26 These streams may be configured independently using the standard library's
27 `logging` module.  For example, you may wish to send ``tornado.access`` logs
28 to a separate file for analysis.
29 """
30 import logging
31 import logging.handlers
32 import sys
33 
34 from tornado.escape import _unicode
35 from tornado.util import unicode_type, basestring_type
36 
37 try:
38     import colorama  # type: ignore
39 except ImportError:
40     colorama = None
41 
42 try:
43     import curses
44 except ImportError:
45     curses = None  # type: ignore
46 
47 from typing import Dict, Any, cast
48 
49 # Logger objects for internal tornado use
50 access_log = logging.getLogger("tornado.access")
51 app_log = logging.getLogger("tornado.application")
52 gen_log = logging.getLogger("tornado.general")
53 
54 
55 def _stderr_supports_color() -> bool:
56     try:
57         if hasattr(sys.stderr, "isatty") and sys.stderr.isatty():
58             if curses:
59                 curses.setupterm()
60                 if curses.tigetnum("colors") > 0:
61                     return True
62             elif colorama:
63                 if sys.stderr is getattr(
64                     colorama.initialise, "wrapped_stderr", object()
65                 ):
66                     return True
67     except Exception:
68         # Very broad exception handling because it's always better to
69         # fall back to non-colored logs than to break at startup.
70         pass
71     return False
72 
73 
74 def _safe_unicode(s: Any) -> str:
75     try:
76         return _unicode(s)
77     except UnicodeDecodeError:
78         return repr(s)
79 
80 
81 class LogFormatter(logging.Formatter):
82     """Log formatter used in Tornado.
83 
84     Key features of this formatter are:
85 
86     * Color support when logging to a terminal that supports it.
87     * Timestamps on every log line.
88     * Robust against str/bytes encoding problems.
89 
90     This formatter is enabled automatically by
91     `tornado.options.parse_command_line` or `tornado.options.parse_config_file`
92     (unless ``--logging=none`` is used).
93 
94     Color support on Windows versions that do not support ANSI color codes is
95     enabled by use of the colorama__ library. Applications that wish to use
96     this must first initialize colorama with a call to ``colorama.init``.
97     See the colorama documentation for details.
98 
99     __ https://pypi.python.org/pypi/colorama
100 
101     .. versionchanged:: 4.5
102        Added support for ``colorama``. Changed the constructor
103        signature to be compatible with `logging.config.dictConfig`.
104     """
105 
106     DEFAULT_FORMAT = "%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s"  # noqa: E501
107     DEFAULT_DATE_FORMAT = "%y%m%d %H:%M:%S"
108     DEFAULT_COLORS = {
109         logging.DEBUG: 4,  # Blue
110         logging.INFO: 2,  # Green
111         logging.WARNING: 3,  # Yellow
112         logging.ERROR: 1,  # Red
113     }
114 
115     def __init__(
116         self,
117         fmt: str = DEFAULT_FORMAT,
118         datefmt: str = DEFAULT_DATE_FORMAT,
119         style: str = "%",
120         color: bool = True,
121         colors: Dict[int, int] = DEFAULT_COLORS,
122     ) -> None:
123         r"""
124         :arg bool color: Enables color support.
125         :arg str fmt: Log message format.
126           It will be applied to the attributes dict of log records. The
127           text between ``%(color)s`` and ``%(end_color)s`` will be colored
128           depending on the level if color support is on.
129         :arg dict colors: color mappings from logging level to terminal color
130           code
131         :arg str datefmt: Datetime format.
132           Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``.
133 
134         .. versionchanged:: 3.2
135 
136            Added ``fmt`` and ``datefmt`` arguments.
137         """
138         logging.Formatter.__init__(self, datefmt=datefmt)
139         self._fmt = fmt
140 
141         self._colors = {}  # type: Dict[int, str]
142         if color and _stderr_supports_color():
143             if curses is not None:
144                 fg_color = curses.tigetstr("setaf") or curses.tigetstr("setf") or b""
145 
146                 for levelno, code in colors.items():
147                     # Convert the terminal control characters from
148                     # bytes to unicode strings for easier use with the
149                     # logging module.
150                     self._colors[levelno] = unicode_type(
151                         curses.tparm(fg_color, code), "ascii"
152                     )
153                 self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
154             else:
155                 # If curses is not present (currently we'll only get here for
156                 # colorama on windows), assume hard-coded ANSI color codes.
157                 for levelno, code in colors.items():
158                     self._colors[levelno] = "\033[2;3%dm" % code
159                 self._normal = "\033[0m"
160         else:
161             self._normal = ""
162 
163     def format(self, record: Any) -> str:
164         try:
165             message = record.getMessage()
166             assert isinstance(message, basestring_type)  # guaranteed by logging
167             # Encoding notes:  The logging module prefers to work with character
168             # strings, but only enforces that log messages are instances of
169             # basestring.  In python 2, non-ascii bytestrings will make
170             # their way through the logging framework until they blow up with
171             # an unhelpful decoding error (with this formatter it happens
172             # when we attach the prefix, but there are other opportunities for
173             # exceptions further along in the framework).
174             #
175             # If a byte string makes it this far, convert it to unicode to
176             # ensure it will make it out to the logs.  Use repr() as a fallback
177             # to ensure that all byte strings can be converted successfully,
178             # but don't do it by default so we don't add extra quotes to ascii
179             # bytestrings.  This is a bit of a hacky place to do this, but
180             # it's worth it since the encoding errors that would otherwise
181             # result are so useless (and tornado is fond of using utf8-encoded
182             # byte strings wherever possible).
183             record.message = _safe_unicode(message)
184         except Exception as e:
185             record.message = "Bad message (%r): %r" % (e, record.__dict__)
186 
187         record.asctime = self.formatTime(record, cast(str, self.datefmt))
188 
189         if record.levelno in self._colors:
190             record.color = self._colors[record.levelno]
191             record.end_color = self._normal
192         else:
193             record.color = record.end_color = ""
194 
195         formatted = self._fmt % record.__dict__
196 
197         if record.exc_info:
198             if not record.exc_text:
199                 record.exc_text = self.formatException(record.exc_info)
200         if record.exc_text:
201             # exc_text contains multiple lines.  We need to _safe_unicode
202             # each line separately so that non-utf8 bytes don't cause
203             # all the newlines to turn into '\n'.
204             lines = [formatted.rstrip()]
205             lines.extend(_safe_unicode(ln) for ln in record.exc_text.split("\n"))
206             formatted = "\n".join(lines)
207         return formatted.replace("\n", "\n    ")
208 
209 
210 def enable_pretty_logging(options: Any = None, logger: logging.Logger = None) -> None:
211     """Turns on formatted logging output as configured.
212 
213     This is called automatically by `tornado.options.parse_command_line`
214     and `tornado.options.parse_config_file`.
215     """
216     if options is None:
217         import tornado.options
218 
219         options = tornado.options.options
220     if options.logging is None or options.logging.lower() == "none":
221         return
222     if logger is None:
223         logger = logging.getLogger()
224     logger.setLevel(getattr(logging, options.logging.upper()))
225     if options.log_file_prefix:
226         rotate_mode = options.log_rotate_mode
227         if rotate_mode == "size":
228             channel = logging.handlers.RotatingFileHandler(
229                 filename=options.log_file_prefix,
230                 maxBytes=options.log_file_max_size,
231                 backupCount=options.log_file_num_backups,
232                 encoding="utf-8",
233             )  # type: logging.Handler
234         elif rotate_mode == "time":
235             channel = logging.handlers.TimedRotatingFileHandler(
236                 filename=options.log_file_prefix,
237                 when=options.log_rotate_when,
238                 interval=options.log_rotate_interval,
239                 backupCount=options.log_file_num_backups,
240                 encoding="utf-8",
241             )
242         else:
243             error_message = (
244                 "The value of log_rotate_mode option should be "
245                 + '"size" or "time", not "%s".' % rotate_mode
246             )
247             raise ValueError(error_message)
248         channel.setFormatter(LogFormatter(color=False))
249         logger.addHandler(channel)
250 
251     if options.log_to_stderr or (options.log_to_stderr is None and not logger.handlers):
252         # Set up color if we are in a tty and curses is installed
253         channel = logging.StreamHandler()
254         channel.setFormatter(LogFormatter())
255         logger.addHandler(channel)
256 
257 
258 def define_logging_options(options: Any = None) -> None:
259     """Add logging-related flags to ``options``.
260 
261     These options are present automatically on the default options instance;
262     this method is only necessary if you have created your own `.OptionParser`.
263 
264     .. versionadded:: 4.2
265         This function existed in prior versions but was broken and undocumented until 4.2.
266     """
267     if options is None:
268         # late import to prevent cycle
269         import tornado.options
270 
271         options = tornado.options.options
272     options.define(
273         "logging",
274         default="info",
275         help=(
276             "Set the Python log level. If 'none', tornado won't touch the "
277             "logging configuration."
278         ),
279         metavar="debug|info|warning|error|none",
280     )
281     options.define(
282         "log_to_stderr",
283         type=bool,
284         default=None,
285         help=(
286             "Send log output to stderr (colorized if possible). "
287             "By default use stderr if --log_file_prefix is not set and "
288             "no other logging is configured."
289         ),
290     )
291     options.define(
292         "log_file_prefix",
293         type=str,
294         default=None,
295         metavar="PATH",
296         help=(
297             "Path prefix for log files. "
298             "Note that if you are running multiple tornado processes, "
299             "log_file_prefix must be different for each of them (e.g. "
300             "include the port number)"
301         ),
302     )
303     options.define(
304         "log_file_max_size",
305         type=int,
306         default=100 * 1000 * 1000,
307         help="max size of log files before rollover",
308     )
309     options.define(
310         "log_file_num_backups", type=int, default=10, help="number of log files to keep"
311     )
312 
313     options.define(
314         "log_rotate_when",
315         type=str,
316         default="midnight",
317         help=(
318             "specify the type of TimedRotatingFileHandler interval "
319             "other options:('S', 'M', 'H', 'D', 'W0'-'W6')"
320         ),
321     )
322     options.define(
323         "log_rotate_interval",
324         type=int,
325         default=1,
326         help="The interval value of timed rotating",
327     )
328 
329     options.define(
330         "log_rotate_mode",
331         type=str,
332         default="size",
333         help="The mode of rotating files(time or size)",
334     )
335 
336     options.add_parse_callback(lambda: enable_pretty_logging(options))
337
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/tornado/log.py b/tornado/log.py
--- a/tornado/log.py
+++ b/tornado/log.py
@@ -110,6 +110,7 @@
         logging.INFO: 2,  # Green
         logging.WARNING: 3,  # Yellow
         logging.ERROR: 1,  # Red
+        logging.CRITICAL: 5,  # Magenta
     }
 
     def __init__(

{"golden_diff": "diff --git a/tornado/log.py b/tornado/log.py\n--- a/tornado/log.py\n+++ b/tornado/log.py\n@@ -110,6 +110,7 @@\n         logging.INFO: 2,  # Green\n         logging.WARNING: 3,  # Yellow\n         logging.ERROR: 1,  # Red\n+        logging.CRITICAL: 5,  # Magenta\n     }\n \n     def __init__(\n", "issue": "LogFormatter DEFAULT_COLORS needs a logging.CRITICAL entry\nhttps://github.com/tornadoweb/tornado/blob/c447875a1058f4768c2995ddd9ebb0eaddd3f32e/tornado/log.py#L108-L113\r\n\r\nCurrently `ERROR` will log red, but `CRITICAL` will log in white.  Curses `COLOR_MAGENTA` (5) is probably the best option.\n", "before_files": [{"content": "#\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\"\"\"\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 colorama  # type: ignore\nexcept ImportError:\n    colorama = None\n\ntry:\n    import curses\nexcept ImportError:\n    curses = None  # type: ignore\n\nfrom typing import Dict, Any, cast\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() -> bool:\n    try:\n        if hasattr(sys.stderr, \"isatty\") and sys.stderr.isatty():\n            if curses:\n                curses.setupterm()\n                if curses.tigetnum(\"colors\") > 0:\n                    return True\n            elif colorama:\n                if sys.stderr is getattr(\n                    colorama.initialise, \"wrapped_stderr\", object()\n                ):\n                    return True\n    except Exception:\n        # Very broad exception handling because it's always better to\n        # fall back to non-colored logs than to break at startup.\n        pass\n    return False\n\n\ndef _safe_unicode(s: Any) -> str:\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` or `tornado.options.parse_config_file`\n    (unless ``--logging=none`` is used).\n\n    Color support on Windows versions that do not support ANSI color codes is\n    enabled by use of the colorama__ library. Applications that wish to use\n    this must first initialize colorama with a call to ``colorama.init``.\n    See the colorama documentation for details.\n\n    __ https://pypi.python.org/pypi/colorama\n\n    .. versionchanged:: 4.5\n       Added support for ``colorama``. Changed the constructor\n       signature to be compatible with `logging.config.dictConfig`.\n    \"\"\"\n\n    DEFAULT_FORMAT = \"%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s\"  # noqa: E501\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__(\n        self,\n        fmt: str = DEFAULT_FORMAT,\n        datefmt: str = DEFAULT_DATE_FORMAT,\n        style: str = \"%\",\n        color: bool = True,\n        colors: Dict[int, int] = DEFAULT_COLORS,\n    ) -> None:\n        r\"\"\"\n        :arg bool color: Enables color support.\n        :arg str 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 str 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 = {}  # type: Dict[int, str]\n        if color and _stderr_supports_color():\n            if curses is not None:\n                fg_color = curses.tigetstr(\"setaf\") or curses.tigetstr(\"setf\") or b\"\"\n\n                for levelno, code in colors.items():\n                    # Convert the terminal control characters from\n                    # bytes to unicode strings for easier use with the\n                    # logging module.\n                    self._colors[levelno] = unicode_type(\n                        curses.tparm(fg_color, code), \"ascii\"\n                    )\n                self._normal = unicode_type(curses.tigetstr(\"sgr0\"), \"ascii\")\n            else:\n                # If curses is not present (currently we'll only get here for\n                # colorama on windows), assume hard-coded ANSI color codes.\n                for levelno, code in colors.items():\n                    self._colors[levelno] = \"\\033[2;3%dm\" % code\n                self._normal = \"\\033[0m\"\n        else:\n            self._normal = \"\"\n\n    def format(self, record: Any) -> str:\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 wherever 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, cast(str, 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: Any = None, logger: logging.Logger = None) -> 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        import tornado.options\n\n        options = tornado.options.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        rotate_mode = options.log_rotate_mode\n        if rotate_mode == \"size\":\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                encoding=\"utf-8\",\n            )  # type: logging.Handler\n        elif rotate_mode == \"time\":\n            channel = logging.handlers.TimedRotatingFileHandler(\n                filename=options.log_file_prefix,\n                when=options.log_rotate_when,\n                interval=options.log_rotate_interval,\n                backupCount=options.log_file_num_backups,\n                encoding=\"utf-8\",\n            )\n        else:\n            error_message = (\n                \"The value of log_rotate_mode option should be \"\n                + '\"size\" or \"time\", not \"%s\".' % rotate_mode\n            )\n            raise ValueError(error_message)\n        channel.setFormatter(LogFormatter(color=False))\n        logger.addHandler(channel)\n\n    if options.log_to_stderr or (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: Any = None) -> 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        import tornado.options\n\n        options = tornado.options.options\n    options.define(\n        \"logging\",\n        default=\"info\",\n        help=(\n            \"Set the Python log level. If 'none', tornado won't touch the \"\n            \"logging configuration.\"\n        ),\n        metavar=\"debug|info|warning|error|none\",\n    )\n    options.define(\n        \"log_to_stderr\",\n        type=bool,\n        default=None,\n        help=(\n            \"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        ),\n    )\n    options.define(\n        \"log_file_prefix\",\n        type=str,\n        default=None,\n        metavar=\"PATH\",\n        help=(\n            \"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        ),\n    )\n    options.define(\n        \"log_file_max_size\",\n        type=int,\n        default=100 * 1000 * 1000,\n        help=\"max size of log files before rollover\",\n    )\n    options.define(\n        \"log_file_num_backups\", type=int, default=10, help=\"number of log files to keep\"\n    )\n\n    options.define(\n        \"log_rotate_when\",\n        type=str,\n        default=\"midnight\",\n        help=(\n            \"specify the type of TimedRotatingFileHandler interval \"\n            \"other options:('S', 'M', 'H', 'D', 'W0'-'W6')\"\n        ),\n    )\n    options.define(\n        \"log_rotate_interval\",\n        type=int,\n        default=1,\n        help=\"The interval value of timed rotating\",\n    )\n\n    options.define(\n        \"log_rotate_mode\",\n        type=str,\n        default=\"size\",\n        help=\"The mode of rotating files(time or size)\",\n    )\n\n    options.add_parse_callback(lambda: enable_pretty_logging(options))\n", "path": "tornado/log.py"}], "after_files": [{"content": "#\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\"\"\"\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 colorama  # type: ignore\nexcept ImportError:\n    colorama = None\n\ntry:\n    import curses\nexcept ImportError:\n    curses = None  # type: ignore\n\nfrom typing import Dict, Any, cast\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() -> bool:\n    try:\n        if hasattr(sys.stderr, \"isatty\") and sys.stderr.isatty():\n            if curses:\n                curses.setupterm()\n                if curses.tigetnum(\"colors\") > 0:\n                    return True\n            elif colorama:\n                if sys.stderr is getattr(\n                    colorama.initialise, \"wrapped_stderr\", object()\n                ):\n                    return True\n    except Exception:\n        # Very broad exception handling because it's always better to\n        # fall back to non-colored logs than to break at startup.\n        pass\n    return False\n\n\ndef _safe_unicode(s: Any) -> str:\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` or `tornado.options.parse_config_file`\n    (unless ``--logging=none`` is used).\n\n    Color support on Windows versions that do not support ANSI color codes is\n    enabled by use of the colorama__ library. Applications that wish to use\n    this must first initialize colorama with a call to ``colorama.init``.\n    See the colorama documentation for details.\n\n    __ https://pypi.python.org/pypi/colorama\n\n    .. versionchanged:: 4.5\n       Added support for ``colorama``. Changed the constructor\n       signature to be compatible with `logging.config.dictConfig`.\n    \"\"\"\n\n    DEFAULT_FORMAT = \"%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s\"  # noqa: E501\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        logging.CRITICAL: 5,  # Magenta\n    }\n\n    def __init__(\n        self,\n        fmt: str = DEFAULT_FORMAT,\n        datefmt: str = DEFAULT_DATE_FORMAT,\n        style: str = \"%\",\n        color: bool = True,\n        colors: Dict[int, int] = DEFAULT_COLORS,\n    ) -> None:\n        r\"\"\"\n        :arg bool color: Enables color support.\n        :arg str 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 str 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 = {}  # type: Dict[int, str]\n        if color and _stderr_supports_color():\n            if curses is not None:\n                fg_color = curses.tigetstr(\"setaf\") or curses.tigetstr(\"setf\") or b\"\"\n\n                for levelno, code in colors.items():\n                    # Convert the terminal control characters from\n                    # bytes to unicode strings for easier use with the\n                    # logging module.\n                    self._colors[levelno] = unicode_type(\n                        curses.tparm(fg_color, code), \"ascii\"\n                    )\n                self._normal = unicode_type(curses.tigetstr(\"sgr0\"), \"ascii\")\n            else:\n                # If curses is not present (currently we'll only get here for\n                # colorama on windows), assume hard-coded ANSI color codes.\n                for levelno, code in colors.items():\n                    self._colors[levelno] = \"\\033[2;3%dm\" % code\n                self._normal = \"\\033[0m\"\n        else:\n            self._normal = \"\"\n\n    def format(self, record: Any) -> str:\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 wherever 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, cast(str, 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: Any = None, logger: logging.Logger = None) -> 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        import tornado.options\n\n        options = tornado.options.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        rotate_mode = options.log_rotate_mode\n        if rotate_mode == \"size\":\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                encoding=\"utf-8\",\n            )  # type: logging.Handler\n        elif rotate_mode == \"time\":\n            channel = logging.handlers.TimedRotatingFileHandler(\n                filename=options.log_file_prefix,\n                when=options.log_rotate_when,\n                interval=options.log_rotate_interval,\n                backupCount=options.log_file_num_backups,\n                encoding=\"utf-8\",\n            )\n        else:\n            error_message = (\n                \"The value of log_rotate_mode option should be \"\n                + '\"size\" or \"time\", not \"%s\".' % rotate_mode\n            )\n            raise ValueError(error_message)\n        channel.setFormatter(LogFormatter(color=False))\n        logger.addHandler(channel)\n\n    if options.log_to_stderr or (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: Any = None) -> 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        import tornado.options\n\n        options = tornado.options.options\n    options.define(\n        \"logging\",\n        default=\"info\",\n        help=(\n            \"Set the Python log level. If 'none', tornado won't touch the \"\n            \"logging configuration.\"\n        ),\n        metavar=\"debug|info|warning|error|none\",\n    )\n    options.define(\n        \"log_to_stderr\",\n        type=bool,\n        default=None,\n        help=(\n            \"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        ),\n    )\n    options.define(\n        \"log_file_prefix\",\n        type=str,\n        default=None,\n        metavar=\"PATH\",\n        help=(\n            \"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        ),\n    )\n    options.define(\n        \"log_file_max_size\",\n        type=int,\n        default=100 * 1000 * 1000,\n        help=\"max size of log files before rollover\",\n    )\n    options.define(\n        \"log_file_num_backups\", type=int, default=10, help=\"number of log files to keep\"\n    )\n\n    options.define(\n        \"log_rotate_when\",\n        type=str,\n        default=\"midnight\",\n        help=(\n            \"specify the type of TimedRotatingFileHandler interval \"\n            \"other options:('S', 'M', 'H', 'D', 'W0'-'W6')\"\n        ),\n    )\n    options.define(\n        \"log_rotate_interval\",\n        type=int,\n        default=1,\n        help=\"The interval value of timed rotating\",\n    )\n\n    options.define(\n        \"log_rotate_mode\",\n        type=str,\n        default=\"size\",\n        help=\"The mode of rotating files(time or size)\",\n    )\n\n    options.add_parse_callback(lambda: enable_pretty_logging(options))\n", "path": "tornado/log.py"}]}