We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Include logger name in log output
The culprit is logged, but the new "short" log format doesn't include the logger name so I don't get any useful information from this. IMO the default log format should include the logger name.
https://github.com/cocotb/cocotb/blob/c69454db92388a8915c99a35ca9cba06565fe4d5/cocotb/scheduler.py#L451

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cocotb/log.py`
Content:
```
1 # Copyright (c) 2013, 2018 Potential Ventures Ltd
2 # Copyright (c) 2013 SolarFlare Communications Inc
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
7 #     * Redistributions of source code must retain the above copyright
8 #       notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above copyright
10 #       notice, this list of conditions and the following disclaimer in the
11 #       documentation and/or other materials provided with the distribution.
12 #     * Neither the name of Potential Ventures Ltd,
13 #       SolarFlare Communications Inc nor the
14 #       names of its contributors may be used to endorse or promote products
15 #       derived from this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
21 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 """
29 Everything related to logging
30 """
31 
32 import logging
33 import os
34 import sys
35 import warnings
36 
37 import cocotb.ANSI as ANSI
38 from cocotb import simulator
39 from cocotb.utils import get_sim_time, get_time_from_sim_steps, want_color_output
40 
41 try:
42     _suppress = int(os.environ.get("COCOTB_REDUCED_LOG_FMT", "1"))
43 except ValueError:
44     _suppress = 1
45 
46 # Column alignment
47 _LEVEL_CHARS = len("CRITICAL")  # noqa
48 _RECORD_CHARS = 35  # noqa
49 _FILENAME_CHARS = 20  # noqa
50 _LINENO_CHARS = 4  # noqa
51 _FUNCNAME_CHARS = 31  # noqa
52 
53 # Custom log level
54 logging.TRACE = 5
55 logging.addLevelName(5, "TRACE")
56 
57 # Default log level if not overwritten by the user.
58 _COCOTB_LOG_LEVEL_DEFAULT = "INFO"
59 
60 
61 def default_config():
62     """Apply the default cocotb log formatting to the root logger.
63 
64     This hooks up the logger to write to stdout, using either
65     :class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending
66     on whether colored output is requested. It also adds a
67     :class:`SimTimeContextFilter` filter so that
68     :attr:`~logging.LogRecord.created_sim_time` is available to the formatter.
69 
70     The logging level for cocotb logs is set based on the
71     :envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``.
72 
73     If desired, this logging configuration can be overwritten by calling
74     ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by
75     manually resetting the root logger instance.
76     An example of this can be found in the section on :ref:`rotating-logger`.
77 
78     .. versionadded:: 1.4
79     """
80     # construct an appropriate handler
81     hdlr = logging.StreamHandler(sys.stdout)
82     hdlr.addFilter(SimTimeContextFilter())
83     if want_color_output():
84         hdlr.setFormatter(SimColourLogFormatter())
85     else:
86         hdlr.setFormatter(SimLogFormatter())
87 
88     logging.setLoggerClass(SimBaseLog)  # For backwards compatibility
89     logging.basicConfig()
90     logging.getLogger().handlers = [hdlr]  # overwrite default handlers
91 
92     # apply level settings for cocotb
93     log = logging.getLogger("cocotb")
94 
95     try:
96         # All log levels are upper case, convert the user input for convenience.
97         level = os.environ["COCOTB_LOG_LEVEL"].upper()
98     except KeyError:
99         level = _COCOTB_LOG_LEVEL_DEFAULT
100 
101     try:
102         log.setLevel(level)
103     except ValueError:
104         valid_levels = ("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE")
105         raise ValueError(
106             "Invalid log level %r passed through the "
107             "COCOTB_LOG_LEVEL environment variable. Valid log "
108             "levels: %s" % (level, ", ".join(valid_levels))
109         )
110 
111     # Notify GPI of log level, which it uses as an optimization to avoid
112     # calling into Python.
113     simulator.log_level(log.getEffectiveLevel())
114 
115 
116 class SimBaseLog(logging.getLoggerClass()):
117     """This class only exists for backwards compatibility"""
118 
119     @property
120     def logger(self):
121         warnings.warn(
122             "the .logger attribute should not be used now that `SimLog` "
123             "returns a native logger instance directly.",
124             DeprecationWarning,
125             stacklevel=2,
126         )
127         return self
128 
129     @property
130     def colour(self):
131         warnings.warn(
132             "the .colour attribute may be removed in future, use the "
133             "equivalent `cocotb.utils.want_color_output()` instead",
134             DeprecationWarning,
135             stacklevel=2,
136         )
137         return want_color_output()
138 
139     def setLevel(self, level: int) -> None:
140         super().setLevel(level)
141         if self.name == "gpi":
142             simulator.log_level(level)
143 
144 
145 # this used to be a class, hence the unusual capitalization
146 def SimLog(name, ident=None):
147     """Like logging.getLogger, but append a numeric identifier to the name"""
148     if ident is not None:
149         name = f"{name}.0x{ident:x}"
150     return logging.getLogger(name)
151 
152 
153 class SimTimeContextFilter(logging.Filter):
154     """
155     A filter to inject simulator times into the log records.
156 
157     This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`.
158 
159     This adds the :attr:`~logging.LogRecord.created_sim_time` attribute.
160 
161     .. versionadded:: 1.4
162     """
163 
164     # needed to make our docs render well
165     def __init__(self):
166         """"""
167         super().__init__()
168 
169     def filter(self, record):
170         try:
171             record.created_sim_time = get_sim_time()
172         except RecursionError:
173             # get_sim_time may try to log - if that happens, we can't
174             # attach a simulator time to this message.
175             record.created_sim_time = None
176         return True
177 
178 
179 class SimLogFormatter(logging.Formatter):
180     """Log formatter to provide consistent log message handling.
181 
182     This will only add simulator timestamps if the handler object this
183     formatter is attached to has a :class:`SimTimeContextFilter` filter
184     attached, which cocotb ensures by default.
185     """
186 
187     # Removes the arguments from the base class. Docstring needed to make
188     # sphinx happy.
189     def __init__(self):
190         """Takes no arguments."""
191         super().__init__()
192 
193     # Justify and truncate
194     @staticmethod
195     def ljust(string, chars):
196         if len(string) > chars:
197             return ".." + string[(chars - 2) * -1 :]
198         return string.ljust(chars)
199 
200     @staticmethod
201     def rjust(string, chars):
202         if len(string) > chars:
203             return ".." + string[(chars - 2) * -1 :]
204         return string.rjust(chars)
205 
206     def _format(self, level, record, msg, coloured=False):
207         sim_time = getattr(record, "created_sim_time", None)
208         if sim_time is None:
209             sim_time_str = "  -.--ns"
210         else:
211             time_ns = get_time_from_sim_steps(sim_time, "ns")
212             sim_time_str = f"{time_ns:6.2f}ns"
213         prefix = sim_time_str.rjust(11) + " " + level + " "
214         if not _suppress:
215             prefix += (
216                 self.ljust(record.name, _RECORD_CHARS)
217                 + self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)
218                 + ":"
219                 + self.ljust(str(record.lineno), _LINENO_CHARS)
220                 + " in "
221                 + self.ljust(str(record.funcName), _FUNCNAME_CHARS)
222                 + " "
223             )
224 
225         # these lines are copied from the builtin logger
226         if record.exc_info:
227             # Cache the traceback text to avoid converting it multiple times
228             # (it's constant anyway)
229             if not record.exc_text:
230                 record.exc_text = self.formatException(record.exc_info)
231         if record.exc_text:
232             if msg[-1:] != "\n":
233                 msg = msg + "\n"
234             msg = msg + record.exc_text
235 
236         prefix_len = len(prefix)
237         if coloured:
238             prefix_len -= len(level) - _LEVEL_CHARS
239         pad = "\n" + " " * (prefix_len)
240         return prefix + pad.join(msg.split("\n"))
241 
242     def format(self, record):
243         """Prettify the log output, annotate with simulation time"""
244 
245         msg = record.getMessage()
246         level = record.levelname.ljust(_LEVEL_CHARS)
247 
248         return self._format(level, record, msg)
249 
250 
251 class SimColourLogFormatter(SimLogFormatter):
252     """Log formatter to provide consistent log message handling."""
253 
254     loglevel2colour = {
255         logging.TRACE: "%s",
256         logging.DEBUG: "%s",
257         logging.INFO: "%s",
258         logging.WARNING: ANSI.COLOR_WARNING + "%s" + ANSI.COLOR_DEFAULT,
259         logging.ERROR: ANSI.COLOR_ERROR + "%s" + ANSI.COLOR_DEFAULT,
260         logging.CRITICAL: ANSI.COLOR_CRITICAL + "%s" + ANSI.COLOR_DEFAULT,
261     }
262 
263     def format(self, record):
264         """Prettify the log output, annotate with simulation time"""
265 
266         msg = record.getMessage()
267 
268         # Need to colour each line in case coloring is applied in the message
269         msg = "\n".join(
270             [
271                 SimColourLogFormatter.loglevel2colour.get(record.levelno, "%s") % line
272                 for line in msg.split("\n")
273             ]
274         )
275         level = SimColourLogFormatter.loglevel2colour.get(
276             record.levelno, "%s"
277         ) % record.levelname.ljust(_LEVEL_CHARS)
278 
279         return self._format(level, record, msg, coloured=True)
280 
281 
282 def _filter_from_c(logger_name, level):
283     return logging.getLogger(logger_name).isEnabledFor(level)
284 
285 
286 def _log_from_c(logger_name, level, filename, lineno, msg, function_name):
287     """
288     This is for use from the C world, and allows us to insert C stack
289     information.
290     """
291     logger = logging.getLogger(logger_name)
292     if logger.isEnabledFor(level):
293         record = logger.makeRecord(
294             logger.name, level, filename, lineno, msg, None, None, function_name
295         )
296         logger.handle(record)
297
```
--- 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/cocotb/log.py b/cocotb/log.py
--- a/cocotb/log.py
+++ b/cocotb/log.py
@@ -44,11 +44,11 @@
     _suppress = 1
 
 # Column alignment
-_LEVEL_CHARS = len("CRITICAL")  # noqa
-_RECORD_CHARS = 35  # noqa
-_FILENAME_CHARS = 20  # noqa
-_LINENO_CHARS = 4  # noqa
-_FUNCNAME_CHARS = 31  # noqa
+_LEVEL_CHARS = len("CRITICAL")
+_RECORD_CHARS = 34
+_FILENAME_CHARS = 20
+_LINENO_CHARS = 4
+_FUNCNAME_CHARS = 31
 
 # Custom log level
 logging.TRACE = 5
@@ -210,11 +210,17 @@
         else:
             time_ns = get_time_from_sim_steps(sim_time, "ns")
             sim_time_str = f"{time_ns:6.2f}ns"
-        prefix = sim_time_str.rjust(11) + " " + level + " "
+        prefix = (
+            sim_time_str.rjust(11)
+            + " "
+            + level
+            + " "
+            + self.ljust(record.name, _RECORD_CHARS)
+            + " "
+        )
         if not _suppress:
             prefix += (
-                self.ljust(record.name, _RECORD_CHARS)
-                + self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)
+                self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)
                 + ":"
                 + self.ljust(str(record.lineno), _LINENO_CHARS)
                 + " in "

{"golden_diff": "diff --git a/cocotb/log.py b/cocotb/log.py\n--- a/cocotb/log.py\n+++ b/cocotb/log.py\n@@ -44,11 +44,11 @@\n     _suppress = 1\n \n # Column alignment\n-_LEVEL_CHARS = len(\"CRITICAL\")  # noqa\n-_RECORD_CHARS = 35  # noqa\n-_FILENAME_CHARS = 20  # noqa\n-_LINENO_CHARS = 4  # noqa\n-_FUNCNAME_CHARS = 31  # noqa\n+_LEVEL_CHARS = len(\"CRITICAL\")\n+_RECORD_CHARS = 34\n+_FILENAME_CHARS = 20\n+_LINENO_CHARS = 4\n+_FUNCNAME_CHARS = 31\n \n # Custom log level\n logging.TRACE = 5\n@@ -210,11 +210,17 @@\n         else:\n             time_ns = get_time_from_sim_steps(sim_time, \"ns\")\n             sim_time_str = f\"{time_ns:6.2f}ns\"\n-        prefix = sim_time_str.rjust(11) + \" \" + level + \" \"\n+        prefix = (\n+            sim_time_str.rjust(11)\n+            + \" \"\n+            + level\n+            + \" \"\n+            + self.ljust(record.name, _RECORD_CHARS)\n+            + \" \"\n+        )\n         if not _suppress:\n             prefix += (\n-                self.ljust(record.name, _RECORD_CHARS)\n-                + self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)\n+                self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)\n                 + \":\"\n                 + self.ljust(str(record.lineno), _LINENO_CHARS)\n                 + \" in \"\n", "issue": "Include logger name in log output\nThe culprit is logged, but the new \"short\" log format doesn't include the logger name so I don't get any useful information from this. IMO the default log format should include the logger name.\r\nhttps://github.com/cocotb/cocotb/blob/c69454db92388a8915c99a35ca9cba06565fe4d5/cocotb/scheduler.py#L451\n", "before_files": [{"content": "# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#     * Redistributions of source code must retain the above copyright\n#       notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#     * Neither the name of Potential Ventures Ltd,\n#       SolarFlare Communications Inc nor the\n#       names of its contributors may be used to endorse or promote products\n#       derived from this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\"\"\"\nEverything related to logging\n\"\"\"\n\nimport logging\nimport os\nimport sys\nimport warnings\n\nimport cocotb.ANSI as ANSI\nfrom cocotb import simulator\nfrom cocotb.utils import get_sim_time, get_time_from_sim_steps, want_color_output\n\ntry:\n    _suppress = int(os.environ.get(\"COCOTB_REDUCED_LOG_FMT\", \"1\"))\nexcept ValueError:\n    _suppress = 1\n\n# Column alignment\n_LEVEL_CHARS = len(\"CRITICAL\")  # noqa\n_RECORD_CHARS = 35  # noqa\n_FILENAME_CHARS = 20  # noqa\n_LINENO_CHARS = 4  # noqa\n_FUNCNAME_CHARS = 31  # noqa\n\n# Custom log level\nlogging.TRACE = 5\nlogging.addLevelName(5, \"TRACE\")\n\n# Default log level if not overwritten by the user.\n_COCOTB_LOG_LEVEL_DEFAULT = \"INFO\"\n\n\ndef default_config():\n    \"\"\"Apply the default cocotb log formatting to the root logger.\n\n    This hooks up the logger to write to stdout, using either\n    :class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending\n    on whether colored output is requested. It also adds a\n    :class:`SimTimeContextFilter` filter so that\n    :attr:`~logging.LogRecord.created_sim_time` is available to the formatter.\n\n    The logging level for cocotb logs is set based on the\n    :envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``.\n\n    If desired, this logging configuration can be overwritten by calling\n    ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by\n    manually resetting the root logger instance.\n    An example of this can be found in the section on :ref:`rotating-logger`.\n\n    .. versionadded:: 1.4\n    \"\"\"\n    # construct an appropriate handler\n    hdlr = logging.StreamHandler(sys.stdout)\n    hdlr.addFilter(SimTimeContextFilter())\n    if want_color_output():\n        hdlr.setFormatter(SimColourLogFormatter())\n    else:\n        hdlr.setFormatter(SimLogFormatter())\n\n    logging.setLoggerClass(SimBaseLog)  # For backwards compatibility\n    logging.basicConfig()\n    logging.getLogger().handlers = [hdlr]  # overwrite default handlers\n\n    # apply level settings for cocotb\n    log = logging.getLogger(\"cocotb\")\n\n    try:\n        # All log levels are upper case, convert the user input for convenience.\n        level = os.environ[\"COCOTB_LOG_LEVEL\"].upper()\n    except KeyError:\n        level = _COCOTB_LOG_LEVEL_DEFAULT\n\n    try:\n        log.setLevel(level)\n    except ValueError:\n        valid_levels = (\"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\", \"TRACE\")\n        raise ValueError(\n            \"Invalid log level %r passed through the \"\n            \"COCOTB_LOG_LEVEL environment variable. Valid log \"\n            \"levels: %s\" % (level, \", \".join(valid_levels))\n        )\n\n    # Notify GPI of log level, which it uses as an optimization to avoid\n    # calling into Python.\n    simulator.log_level(log.getEffectiveLevel())\n\n\nclass SimBaseLog(logging.getLoggerClass()):\n    \"\"\"This class only exists for backwards compatibility\"\"\"\n\n    @property\n    def logger(self):\n        warnings.warn(\n            \"the .logger attribute should not be used now that `SimLog` \"\n            \"returns a native logger instance directly.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        return self\n\n    @property\n    def colour(self):\n        warnings.warn(\n            \"the .colour attribute may be removed in future, use the \"\n            \"equivalent `cocotb.utils.want_color_output()` instead\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        return want_color_output()\n\n    def setLevel(self, level: int) -> None:\n        super().setLevel(level)\n        if self.name == \"gpi\":\n            simulator.log_level(level)\n\n\n# this used to be a class, hence the unusual capitalization\ndef SimLog(name, ident=None):\n    \"\"\"Like logging.getLogger, but append a numeric identifier to the name\"\"\"\n    if ident is not None:\n        name = f\"{name}.0x{ident:x}\"\n    return logging.getLogger(name)\n\n\nclass SimTimeContextFilter(logging.Filter):\n    \"\"\"\n    A filter to inject simulator times into the log records.\n\n    This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`.\n\n    This adds the :attr:`~logging.LogRecord.created_sim_time` attribute.\n\n    .. versionadded:: 1.4\n    \"\"\"\n\n    # needed to make our docs render well\n    def __init__(self):\n        \"\"\"\"\"\"\n        super().__init__()\n\n    def filter(self, record):\n        try:\n            record.created_sim_time = get_sim_time()\n        except RecursionError:\n            # get_sim_time may try to log - if that happens, we can't\n            # attach a simulator time to this message.\n            record.created_sim_time = None\n        return True\n\n\nclass SimLogFormatter(logging.Formatter):\n    \"\"\"Log formatter to provide consistent log message handling.\n\n    This will only add simulator timestamps if the handler object this\n    formatter is attached to has a :class:`SimTimeContextFilter` filter\n    attached, which cocotb ensures by default.\n    \"\"\"\n\n    # Removes the arguments from the base class. Docstring needed to make\n    # sphinx happy.\n    def __init__(self):\n        \"\"\"Takes no arguments.\"\"\"\n        super().__init__()\n\n    # Justify and truncate\n    @staticmethod\n    def ljust(string, chars):\n        if len(string) > chars:\n            return \"..\" + string[(chars - 2) * -1 :]\n        return string.ljust(chars)\n\n    @staticmethod\n    def rjust(string, chars):\n        if len(string) > chars:\n            return \"..\" + string[(chars - 2) * -1 :]\n        return string.rjust(chars)\n\n    def _format(self, level, record, msg, coloured=False):\n        sim_time = getattr(record, \"created_sim_time\", None)\n        if sim_time is None:\n            sim_time_str = \"  -.--ns\"\n        else:\n            time_ns = get_time_from_sim_steps(sim_time, \"ns\")\n            sim_time_str = f\"{time_ns:6.2f}ns\"\n        prefix = sim_time_str.rjust(11) + \" \" + level + \" \"\n        if not _suppress:\n            prefix += (\n                self.ljust(record.name, _RECORD_CHARS)\n                + self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)\n                + \":\"\n                + self.ljust(str(record.lineno), _LINENO_CHARS)\n                + \" in \"\n                + self.ljust(str(record.funcName), _FUNCNAME_CHARS)\n                + \" \"\n            )\n\n        # these lines are copied from the builtin logger\n        if record.exc_info:\n            # Cache the traceback text to avoid converting it multiple times\n            # (it's constant anyway)\n            if not record.exc_text:\n                record.exc_text = self.formatException(record.exc_info)\n        if record.exc_text:\n            if msg[-1:] != \"\\n\":\n                msg = msg + \"\\n\"\n            msg = msg + record.exc_text\n\n        prefix_len = len(prefix)\n        if coloured:\n            prefix_len -= len(level) - _LEVEL_CHARS\n        pad = \"\\n\" + \" \" * (prefix_len)\n        return prefix + pad.join(msg.split(\"\\n\"))\n\n    def format(self, record):\n        \"\"\"Prettify the log output, annotate with simulation time\"\"\"\n\n        msg = record.getMessage()\n        level = record.levelname.ljust(_LEVEL_CHARS)\n\n        return self._format(level, record, msg)\n\n\nclass SimColourLogFormatter(SimLogFormatter):\n    \"\"\"Log formatter to provide consistent log message handling.\"\"\"\n\n    loglevel2colour = {\n        logging.TRACE: \"%s\",\n        logging.DEBUG: \"%s\",\n        logging.INFO: \"%s\",\n        logging.WARNING: ANSI.COLOR_WARNING + \"%s\" + ANSI.COLOR_DEFAULT,\n        logging.ERROR: ANSI.COLOR_ERROR + \"%s\" + ANSI.COLOR_DEFAULT,\n        logging.CRITICAL: ANSI.COLOR_CRITICAL + \"%s\" + ANSI.COLOR_DEFAULT,\n    }\n\n    def format(self, record):\n        \"\"\"Prettify the log output, annotate with simulation time\"\"\"\n\n        msg = record.getMessage()\n\n        # Need to colour each line in case coloring is applied in the message\n        msg = \"\\n\".join(\n            [\n                SimColourLogFormatter.loglevel2colour.get(record.levelno, \"%s\") % line\n                for line in msg.split(\"\\n\")\n            ]\n        )\n        level = SimColourLogFormatter.loglevel2colour.get(\n            record.levelno, \"%s\"\n        ) % record.levelname.ljust(_LEVEL_CHARS)\n\n        return self._format(level, record, msg, coloured=True)\n\n\ndef _filter_from_c(logger_name, level):\n    return logging.getLogger(logger_name).isEnabledFor(level)\n\n\ndef _log_from_c(logger_name, level, filename, lineno, msg, function_name):\n    \"\"\"\n    This is for use from the C world, and allows us to insert C stack\n    information.\n    \"\"\"\n    logger = logging.getLogger(logger_name)\n    if logger.isEnabledFor(level):\n        record = logger.makeRecord(\n            logger.name, level, filename, lineno, msg, None, None, function_name\n        )\n        logger.handle(record)\n", "path": "cocotb/log.py"}], "after_files": [{"content": "# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#     * Redistributions of source code must retain the above copyright\n#       notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#     * Neither the name of Potential Ventures Ltd,\n#       SolarFlare Communications Inc nor the\n#       names of its contributors may be used to endorse or promote products\n#       derived from this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\"\"\"\nEverything related to logging\n\"\"\"\n\nimport logging\nimport os\nimport sys\nimport warnings\n\nimport cocotb.ANSI as ANSI\nfrom cocotb import simulator\nfrom cocotb.utils import get_sim_time, get_time_from_sim_steps, want_color_output\n\ntry:\n    _suppress = int(os.environ.get(\"COCOTB_REDUCED_LOG_FMT\", \"1\"))\nexcept ValueError:\n    _suppress = 1\n\n# Column alignment\n_LEVEL_CHARS = len(\"CRITICAL\")\n_RECORD_CHARS = 34\n_FILENAME_CHARS = 20\n_LINENO_CHARS = 4\n_FUNCNAME_CHARS = 31\n\n# Custom log level\nlogging.TRACE = 5\nlogging.addLevelName(5, \"TRACE\")\n\n# Default log level if not overwritten by the user.\n_COCOTB_LOG_LEVEL_DEFAULT = \"INFO\"\n\n\ndef default_config():\n    \"\"\"Apply the default cocotb log formatting to the root logger.\n\n    This hooks up the logger to write to stdout, using either\n    :class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending\n    on whether colored output is requested. It also adds a\n    :class:`SimTimeContextFilter` filter so that\n    :attr:`~logging.LogRecord.created_sim_time` is available to the formatter.\n\n    The logging level for cocotb logs is set based on the\n    :envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``.\n\n    If desired, this logging configuration can be overwritten by calling\n    ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by\n    manually resetting the root logger instance.\n    An example of this can be found in the section on :ref:`rotating-logger`.\n\n    .. versionadded:: 1.4\n    \"\"\"\n    # construct an appropriate handler\n    hdlr = logging.StreamHandler(sys.stdout)\n    hdlr.addFilter(SimTimeContextFilter())\n    if want_color_output():\n        hdlr.setFormatter(SimColourLogFormatter())\n    else:\n        hdlr.setFormatter(SimLogFormatter())\n\n    logging.setLoggerClass(SimBaseLog)  # For backwards compatibility\n    logging.basicConfig()\n    logging.getLogger().handlers = [hdlr]  # overwrite default handlers\n\n    # apply level settings for cocotb\n    log = logging.getLogger(\"cocotb\")\n\n    try:\n        # All log levels are upper case, convert the user input for convenience.\n        level = os.environ[\"COCOTB_LOG_LEVEL\"].upper()\n    except KeyError:\n        level = _COCOTB_LOG_LEVEL_DEFAULT\n\n    try:\n        log.setLevel(level)\n    except ValueError:\n        valid_levels = (\"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\", \"TRACE\")\n        raise ValueError(\n            \"Invalid log level %r passed through the \"\n            \"COCOTB_LOG_LEVEL environment variable. Valid log \"\n            \"levels: %s\" % (level, \", \".join(valid_levels))\n        )\n\n    # Notify GPI of log level, which it uses as an optimization to avoid\n    # calling into Python.\n    simulator.log_level(log.getEffectiveLevel())\n\n\nclass SimBaseLog(logging.getLoggerClass()):\n    \"\"\"This class only exists for backwards compatibility\"\"\"\n\n    @property\n    def logger(self):\n        warnings.warn(\n            \"the .logger attribute should not be used now that `SimLog` \"\n            \"returns a native logger instance directly.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        return self\n\n    @property\n    def colour(self):\n        warnings.warn(\n            \"the .colour attribute may be removed in future, use the \"\n            \"equivalent `cocotb.utils.want_color_output()` instead\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        return want_color_output()\n\n    def setLevel(self, level: int) -> None:\n        super().setLevel(level)\n        if self.name == \"gpi\":\n            simulator.log_level(level)\n\n\n# this used to be a class, hence the unusual capitalization\ndef SimLog(name, ident=None):\n    \"\"\"Like logging.getLogger, but append a numeric identifier to the name\"\"\"\n    if ident is not None:\n        name = f\"{name}.0x{ident:x}\"\n    return logging.getLogger(name)\n\n\nclass SimTimeContextFilter(logging.Filter):\n    \"\"\"\n    A filter to inject simulator times into the log records.\n\n    This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`.\n\n    This adds the :attr:`~logging.LogRecord.created_sim_time` attribute.\n\n    .. versionadded:: 1.4\n    \"\"\"\n\n    # needed to make our docs render well\n    def __init__(self):\n        \"\"\"\"\"\"\n        super().__init__()\n\n    def filter(self, record):\n        try:\n            record.created_sim_time = get_sim_time()\n        except RecursionError:\n            # get_sim_time may try to log - if that happens, we can't\n            # attach a simulator time to this message.\n            record.created_sim_time = None\n        return True\n\n\nclass SimLogFormatter(logging.Formatter):\n    \"\"\"Log formatter to provide consistent log message handling.\n\n    This will only add simulator timestamps if the handler object this\n    formatter is attached to has a :class:`SimTimeContextFilter` filter\n    attached, which cocotb ensures by default.\n    \"\"\"\n\n    # Removes the arguments from the base class. Docstring needed to make\n    # sphinx happy.\n    def __init__(self):\n        \"\"\"Takes no arguments.\"\"\"\n        super().__init__()\n\n    # Justify and truncate\n    @staticmethod\n    def ljust(string, chars):\n        if len(string) > chars:\n            return \"..\" + string[(chars - 2) * -1 :]\n        return string.ljust(chars)\n\n    @staticmethod\n    def rjust(string, chars):\n        if len(string) > chars:\n            return \"..\" + string[(chars - 2) * -1 :]\n        return string.rjust(chars)\n\n    def _format(self, level, record, msg, coloured=False):\n        sim_time = getattr(record, \"created_sim_time\", None)\n        if sim_time is None:\n            sim_time_str = \"  -.--ns\"\n        else:\n            time_ns = get_time_from_sim_steps(sim_time, \"ns\")\n            sim_time_str = f\"{time_ns:6.2f}ns\"\n        prefix = (\n            sim_time_str.rjust(11)\n            + \" \"\n            + level\n            + \" \"\n            + self.ljust(record.name, _RECORD_CHARS)\n            + \" \"\n        )\n        if not _suppress:\n            prefix += (\n                self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS)\n                + \":\"\n                + self.ljust(str(record.lineno), _LINENO_CHARS)\n                + \" in \"\n                + self.ljust(str(record.funcName), _FUNCNAME_CHARS)\n                + \" \"\n            )\n\n        # these lines are copied from the builtin logger\n        if record.exc_info:\n            # Cache the traceback text to avoid converting it multiple times\n            # (it's constant anyway)\n            if not record.exc_text:\n                record.exc_text = self.formatException(record.exc_info)\n        if record.exc_text:\n            if msg[-1:] != \"\\n\":\n                msg = msg + \"\\n\"\n            msg = msg + record.exc_text\n\n        prefix_len = len(prefix)\n        if coloured:\n            prefix_len -= len(level) - _LEVEL_CHARS\n        pad = \"\\n\" + \" \" * (prefix_len)\n        return prefix + pad.join(msg.split(\"\\n\"))\n\n    def format(self, record):\n        \"\"\"Prettify the log output, annotate with simulation time\"\"\"\n\n        msg = record.getMessage()\n        level = record.levelname.ljust(_LEVEL_CHARS)\n\n        return self._format(level, record, msg)\n\n\nclass SimColourLogFormatter(SimLogFormatter):\n    \"\"\"Log formatter to provide consistent log message handling.\"\"\"\n\n    loglevel2colour = {\n        logging.TRACE: \"%s\",\n        logging.DEBUG: \"%s\",\n        logging.INFO: \"%s\",\n        logging.WARNING: ANSI.COLOR_WARNING + \"%s\" + ANSI.COLOR_DEFAULT,\n        logging.ERROR: ANSI.COLOR_ERROR + \"%s\" + ANSI.COLOR_DEFAULT,\n        logging.CRITICAL: ANSI.COLOR_CRITICAL + \"%s\" + ANSI.COLOR_DEFAULT,\n    }\n\n    def format(self, record):\n        \"\"\"Prettify the log output, annotate with simulation time\"\"\"\n\n        msg = record.getMessage()\n\n        # Need to colour each line in case coloring is applied in the message\n        msg = \"\\n\".join(\n            [\n                SimColourLogFormatter.loglevel2colour.get(record.levelno, \"%s\") % line\n                for line in msg.split(\"\\n\")\n            ]\n        )\n        level = SimColourLogFormatter.loglevel2colour.get(\n            record.levelno, \"%s\"\n        ) % record.levelname.ljust(_LEVEL_CHARS)\n\n        return self._format(level, record, msg, coloured=True)\n\n\ndef _filter_from_c(logger_name, level):\n    return logging.getLogger(logger_name).isEnabledFor(level)\n\n\ndef _log_from_c(logger_name, level, filename, lineno, msg, function_name):\n    \"\"\"\n    This is for use from the C world, and allows us to insert C stack\n    information.\n    \"\"\"\n    logger = logging.getLogger(logger_name)\n    if logger.isEnabledFor(level):\n        record = logger.makeRecord(\n            logger.name, level, filename, lineno, msg, None, None, function_name\n        )\n        logger.handle(record)\n", "path": "cocotb/log.py"}]}