We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Simulator timestamps are broken in logs
Looks like gh-1411 didn't work properly. I'll try and find the fix shortly, but if we want to do a release before I do we should revert it.

--- 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 os
33 import sys
34 import logging
35 import warnings
36 
37 from cocotb.utils import (
38     get_sim_time, get_time_from_sim_steps, want_color_output
39 )
40 
41 import cocotb.ANSI as ANSI
42 
43 if "COCOTB_REDUCED_LOG_FMT" in os.environ:
44     _suppress = True
45 else:
46     _suppress = False
47 
48 # Column alignment
49 _LEVEL_CHARS    = len("CRITICAL")  # noqa
50 _RECORD_CHARS   = 35  # noqa
51 _FILENAME_CHARS = 20  # noqa
52 _LINENO_CHARS   = 4  # noqa
53 _FUNCNAME_CHARS = 31  # noqa
54 
55 
56 def default_config():
57     """ Apply the default cocotb log formatting to the root logger.
58 
59     This hooks up the logger to write to stdout, using either
60     :class:`SimColourLogFormatter` or :class:`SimLogFormatter` depending
61     on whether colored output is requested. It also adds a
62     :class:`SimTimeContextFilter` filter so that
63     :attr:`~logging.LogRecord.created_sim_time` is available to the formatter.
64 
65     The logging level for cocotb logs is set based on the
66     :envvar:`COCOTB_LOG_LEVEL` environment variable, which defaults to ``INFO``.
67 
68     If desired, this logging configuration can be overwritten by calling
69     ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by
70     manually resetting the root logger instance, for which examples can be
71     found online.
72     """
73     # construct an appropriate handler
74     hdlr = logging.StreamHandler(sys.stdout)
75     if want_color_output():
76         hdlr.setFormatter(SimColourLogFormatter())
77     else:
78         hdlr.setFormatter(SimLogFormatter())
79 
80     filter = SimTimeContextFilter()
81 
82     logging.setLoggerClass(SimBaseLog)  # For backwards compatibility
83     logging.basicConfig()
84     logging.getLogger().handlers = [hdlr]  # overwrite default handlers
85     logging.getLogger().filters = [filter]
86 
87     # apply level settings for cocotb
88     log = logging.getLogger('cocotb')
89     level = os.getenv("COCOTB_LOG_LEVEL", "INFO")
90     try:
91         _default_log = getattr(logging, level)
92     except AttributeError:
93         log.error("Unable to set logging level to %r" % level)
94         _default_log = logging.INFO
95     log.setLevel(_default_log)
96 
97     # Notify GPI of log level, which it uses as an optimization to avoid
98     # calling into Python.
99     if "COCOTB_SIM" in os.environ:
100         import simulator
101         simulator.log_level(_default_log)
102 
103 
104 class SimBaseLog(logging.getLoggerClass()):
105     """ This class only exists for backwards compatibility """
106 
107     @property
108     def logger(self):
109         warnings.warn(
110             "the .logger attribute should not be used now that `SimLog` "
111             "returns a native logger instance directly.",
112             DeprecationWarning, stacklevel=2)
113         return self
114 
115     @property
116     def colour(self):
117         warnings.warn(
118             "the .colour attribute may be removed in future, use the "
119             "equivalent `cocotb.utils.want_color_output()` instead",
120             DeprecationWarning, stacklevel=2)
121         return want_color_output()
122 
123 
124 # this used to be a class, hence the unusual capitalization
125 def SimLog(name, ident=None):
126     """ Like logging.getLogger, but append a numeric identifier to the name """
127     if ident is not None:
128         name = "%s.0x%x" % (name, ident)
129     return logging.getLogger(name)
130 
131 
132 class SimTimeContextFilter(logging.Filter):
133     """
134     A filter to inject simulator times into the log records.
135 
136     This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`.
137 
138     This adds the :attr:`~logging.LogRecord.created_sim_time` attribute.
139     """
140 
141     # needed to make our docs render well
142     def __init__(self, *args, **kwargs):
143         """ See :class:`logging.Filter` for argument descriptions """
144         super().__init__(*args, **kwargs)
145 
146     def filter(self, record):
147         try:
148             record.created_sim_time = get_sim_time()
149         except RecursionError:
150             # get_sim_time may try to log - if that happens, we can't
151             # attach a simulator time to this message.
152             record.created_sim_time = None
153         return True
154 
155 
156 class SimLogFormatter(logging.Formatter):
157     """Log formatter to provide consistent log message handling.
158 
159     This will only add simulator timestamps if the logger object has a
160     :class:`SimTimeContextFilter` filter attached, which cocotb ensures by
161     default.
162     """
163 
164     # Removes the arguments from the base class. Docstring needed to make
165     # sphinx happy.
166     def __init__(self):
167         """ Takes no arguments. """
168         super().__init__()
169 
170     # Justify and truncate
171     @staticmethod
172     def ljust(string, chars):
173         if len(string) > chars:
174             return ".." + string[(chars - 2) * -1:]
175         return string.ljust(chars)
176 
177     @staticmethod
178     def rjust(string, chars):
179         if len(string) > chars:
180             return ".." + string[(chars - 2) * -1:]
181         return string.rjust(chars)
182 
183     def _format(self, level, record, msg, coloured=False):
184         sim_time = getattr(record, 'created_sim_time', None)
185         if sim_time is None:
186             sim_time_str = "  -.--ns"
187         else:
188             time_ns = get_time_from_sim_steps(sim_time, 'ns')
189             sim_time_str = "{:6.2f}ns".format(time_ns)
190         prefix = sim_time_str.rjust(11) + ' ' + level + ' '
191         if not _suppress:
192             prefix += self.ljust(record.name, _RECORD_CHARS) + \
193                       self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS) + \
194                       ':' + self.ljust(str(record.lineno), _LINENO_CHARS) + \
195                       ' in ' + self.ljust(str(record.funcName), _FUNCNAME_CHARS) + ' '
196 
197         # these lines are copied from the builtin logger
198         if record.exc_info:
199             # Cache the traceback text to avoid converting it multiple times
200             # (it's constant anyway)
201             if not record.exc_text:
202                 record.exc_text = self.formatException(record.exc_info)
203         if record.exc_text:
204             if msg[-1:] != "\n":
205                 msg = msg + "\n"
206             msg = msg + record.exc_text
207 
208         prefix_len = len(prefix)
209         if coloured:
210             prefix_len -= (len(level) - _LEVEL_CHARS)
211         pad = "\n" + " " * (prefix_len)
212         return prefix + pad.join(msg.split('\n'))
213 
214     def format(self, record):
215         """Prettify the log output, annotate with simulation time"""
216 
217         msg = record.getMessage()
218         level = record.levelname.ljust(_LEVEL_CHARS)
219 
220         return self._format(level, record, msg)
221 
222 
223 class SimColourLogFormatter(SimLogFormatter):
224     """Log formatter to provide consistent log message handling."""
225 
226     loglevel2colour = {
227         logging.DEBUG   :       "%s",
228         logging.INFO    :       ANSI.COLOR_INFO + "%s" + ANSI.COLOR_DEFAULT,
229         logging.WARNING :       ANSI.COLOR_WARNING + "%s" + ANSI.COLOR_DEFAULT,
230         logging.ERROR   :       ANSI.COLOR_ERROR + "%s" + ANSI.COLOR_DEFAULT,
231         logging.CRITICAL:       ANSI.COLOR_CRITICAL + "%s" + ANSI.COLOR_DEFAULT,
232     }
233 
234     def format(self, record):
235         """Prettify the log output, annotate with simulation time"""
236 
237         msg = record.getMessage()
238 
239         # Need to colour each line in case coloring is applied in the message
240         msg = '\n'.join([SimColourLogFormatter.loglevel2colour[record.levelno] % line for line in msg.split('\n')])
241         level = (SimColourLogFormatter.loglevel2colour[record.levelno] %
242                  record.levelname.ljust(_LEVEL_CHARS))
243 
244         return self._format(level, record, msg, coloured=True)
245 
246 
247 def _filter_from_c(logger_name, level):
248     return logging.getLogger(logger_name).isEnabledFor(level)
249 
250 
251 def _log_from_c(logger_name, level, filename, lineno, msg, function_name):
252     """
253     This is for use from the C world, and allows us to insert C stack
254     information.
255     """
256     logger = logging.getLogger(logger_name)
257     if logger.isEnabledFor(level):
258         record = logger.makeRecord(
259             logger.name,
260             level,
261             filename,
262             lineno,
263             msg,
264             None,
265             None,
266             function_name
267         )
268         logger.handle(record)
269
```
--- 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
@@ -72,17 +72,16 @@
     """
     # construct an appropriate handler
     hdlr = logging.StreamHandler(sys.stdout)
+    hdlr.addFilter(SimTimeContextFilter())
     if want_color_output():
         hdlr.setFormatter(SimColourLogFormatter())
     else:
         hdlr.setFormatter(SimLogFormatter())
 
-    filter = SimTimeContextFilter()
 
     logging.setLoggerClass(SimBaseLog)  # For backwards compatibility
     logging.basicConfig()
     logging.getLogger().handlers = [hdlr]  # overwrite default handlers
-    logging.getLogger().filters = [filter]
 
     # apply level settings for cocotb
     log = logging.getLogger('cocotb')
@@ -139,9 +138,9 @@
     """
 
     # needed to make our docs render well
-    def __init__(self, *args, **kwargs):
-        """ See :class:`logging.Filter` for argument descriptions """
-        super().__init__(*args, **kwargs)
+    def __init__(self):
+        """ Takes no arguments """
+        super().__init__()
 
     def filter(self, record):
         try:
@@ -156,9 +155,9 @@
 class SimLogFormatter(logging.Formatter):
     """Log formatter to provide consistent log message handling.
 
-    This will only add simulator timestamps if the logger object has a
-    :class:`SimTimeContextFilter` filter attached, which cocotb ensures by
-    default.
+    This will only add simulator timestamps if the handler object this
+    formatter is attached to has a :class:`SimTimeContextFilter` filter
+    attached, which cocotb ensures by default.
     """
 
     # Removes the arguments from the base class. Docstring needed to make

{"golden_diff": "diff --git a/cocotb/log.py b/cocotb/log.py\n--- a/cocotb/log.py\n+++ b/cocotb/log.py\n@@ -72,17 +72,16 @@\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-    filter = SimTimeContextFilter()\n \n     logging.setLoggerClass(SimBaseLog)  # For backwards compatibility\n     logging.basicConfig()\n     logging.getLogger().handlers = [hdlr]  # overwrite default handlers\n-    logging.getLogger().filters = [filter]\n \n     # apply level settings for cocotb\n     log = logging.getLogger('cocotb')\n@@ -139,9 +138,9 @@\n     \"\"\"\n \n     # needed to make our docs render well\n-    def __init__(self, *args, **kwargs):\n-        \"\"\" See :class:`logging.Filter` for argument descriptions \"\"\"\n-        super().__init__(*args, **kwargs)\n+    def __init__(self):\n+        \"\"\" Takes no arguments \"\"\"\n+        super().__init__()\n \n     def filter(self, record):\n         try:\n@@ -156,9 +155,9 @@\n class SimLogFormatter(logging.Formatter):\n     \"\"\"Log formatter to provide consistent log message handling.\n \n-    This will only add simulator timestamps if the logger object has a\n-    :class:`SimTimeContextFilter` filter attached, which cocotb ensures by\n-    default.\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", "issue": "Simulator timestamps are broken in logs\nLooks like gh-1411 didn't work properly. I'll try and find the fix shortly, but if we want to do a release before I do we should revert it.\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 os\nimport sys\nimport logging\nimport warnings\n\nfrom cocotb.utils import (\n    get_sim_time, get_time_from_sim_steps, want_color_output\n)\n\nimport cocotb.ANSI as ANSI\n\nif \"COCOTB_REDUCED_LOG_FMT\" in os.environ:\n    _suppress = True\nelse:\n    _suppress = False\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\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, for which examples can be\n    found online.\n    \"\"\"\n    # construct an appropriate handler\n    hdlr = logging.StreamHandler(sys.stdout)\n    if want_color_output():\n        hdlr.setFormatter(SimColourLogFormatter())\n    else:\n        hdlr.setFormatter(SimLogFormatter())\n\n    filter = SimTimeContextFilter()\n\n    logging.setLoggerClass(SimBaseLog)  # For backwards compatibility\n    logging.basicConfig()\n    logging.getLogger().handlers = [hdlr]  # overwrite default handlers\n    logging.getLogger().filters = [filter]\n\n    # apply level settings for cocotb\n    log = logging.getLogger('cocotb')\n    level = os.getenv(\"COCOTB_LOG_LEVEL\", \"INFO\")\n    try:\n        _default_log = getattr(logging, level)\n    except AttributeError:\n        log.error(\"Unable to set logging level to %r\" % level)\n        _default_log = logging.INFO\n    log.setLevel(_default_log)\n\n    # Notify GPI of log level, which it uses as an optimization to avoid\n    # calling into Python.\n    if \"COCOTB_SIM\" in os.environ:\n        import simulator\n        simulator.log_level(_default_log)\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, stacklevel=2)\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, stacklevel=2)\n        return want_color_output()\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 = \"%s.0x%x\" % (name, ident)\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\n    # needed to make our docs render well\n    def __init__(self, *args, **kwargs):\n        \"\"\" See :class:`logging.Filter` for argument descriptions \"\"\"\n        super().__init__(*args, **kwargs)\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 logger object has a\n    :class:`SimTimeContextFilter` filter attached, which cocotb ensures by\n    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 = \"{:6.2f}ns\".format(time_ns)\n        prefix = sim_time_str.rjust(11) + ' ' + level + ' '\n        if not _suppress:\n            prefix += self.ljust(record.name, _RECORD_CHARS) + \\\n                      self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS) + \\\n                      ':' + self.ljust(str(record.lineno), _LINENO_CHARS) + \\\n                      ' in ' + self.ljust(str(record.funcName), _FUNCNAME_CHARS) + ' '\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.DEBUG   :       \"%s\",\n        logging.INFO    :       ANSI.COLOR_INFO + \"%s\" + ANSI.COLOR_DEFAULT,\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([SimColourLogFormatter.loglevel2colour[record.levelno] % line for line in msg.split('\\n')])\n        level = (SimColourLogFormatter.loglevel2colour[record.levelno] %\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,\n            level,\n            filename,\n            lineno,\n            msg,\n            None,\n            None,\n            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 os\nimport sys\nimport logging\nimport warnings\n\nfrom cocotb.utils import (\n    get_sim_time, get_time_from_sim_steps, want_color_output\n)\n\nimport cocotb.ANSI as ANSI\n\nif \"COCOTB_REDUCED_LOG_FMT\" in os.environ:\n    _suppress = True\nelse:\n    _suppress = False\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\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, for which examples can be\n    found online.\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\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    level = os.getenv(\"COCOTB_LOG_LEVEL\", \"INFO\")\n    try:\n        _default_log = getattr(logging, level)\n    except AttributeError:\n        log.error(\"Unable to set logging level to %r\" % level)\n        _default_log = logging.INFO\n    log.setLevel(_default_log)\n\n    # Notify GPI of log level, which it uses as an optimization to avoid\n    # calling into Python.\n    if \"COCOTB_SIM\" in os.environ:\n        import simulator\n        simulator.log_level(_default_log)\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, stacklevel=2)\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, stacklevel=2)\n        return want_color_output()\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 = \"%s.0x%x\" % (name, ident)\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\n    # needed to make our docs render well\n    def __init__(self):\n        \"\"\" Takes no arguments \"\"\"\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 = \"{:6.2f}ns\".format(time_ns)\n        prefix = sim_time_str.rjust(11) + ' ' + level + ' '\n        if not _suppress:\n            prefix += self.ljust(record.name, _RECORD_CHARS) + \\\n                      self.rjust(os.path.split(record.filename)[1], _FILENAME_CHARS) + \\\n                      ':' + self.ljust(str(record.lineno), _LINENO_CHARS) + \\\n                      ' in ' + self.ljust(str(record.funcName), _FUNCNAME_CHARS) + ' '\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.DEBUG   :       \"%s\",\n        logging.INFO    :       ANSI.COLOR_INFO + \"%s\" + ANSI.COLOR_DEFAULT,\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([SimColourLogFormatter.loglevel2colour[record.levelno] % line for line in msg.split('\\n')])\n        level = (SimColourLogFormatter.loglevel2colour[record.levelno] %\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,\n            level,\n            filename,\n            lineno,\n            msg,\n            None,\n            None,\n            function_name\n        )\n        logger.handle(record)\n", "path": "cocotb/log.py"}]}