Repository: cocotb/cocotb

Issue:
GPI: Address DEBUG log spam to cocotb.gpi logger
There are two places that produce lots of DEBUG log statements in the GPI:

https://github.com/cocotb/cocotb/blob/a9cd7ad2625cd8cbfcde3fb5959fb7316b33b4a2/cocotb/share/lib/gpi/GpiCbHdl.cpp#L94-L100

https://github.com/cocotb/cocotb/blob/6eb637ae1ec4110fb3aa10ef04051fe8ef163108/cocotb/share/include/cocotb_utils.h#L57-L73

They are both related to tracing the program flow between GPI and Python.

I'd like to be able to filter out these messages without losing other DEBUG info on the `cocotb.gpi` logger. I would prefer to have them disabled by default with a way to enable them when debugging cocotb issues.

I don't know what the best approach is. New lower log level (#1226)? New distinct logger with a filter?


Discussion:
> New lower log level (#1226)?

Adding `TRACE` as a level, with the corresponding macro functions sound fairly easy to accomplish and conceptually covers both of those chatty cases.

> New distinct logger with a filter?

That's a good bit of work. If you were interested in adding more than one, I'd say build a facility so build more so we can have N. There really are only 4 important numbers: 0, 1, N, and 4 of course... Then we can call out different loggers in the `LOG_*` macros.
@ktbarrett I was leaning towards `TRACE` as well.

`logging.TRACE = 5` ?
Hmm, custom levels can clash with each other. The other approach is probably safer: https://docs.python.org/3.5/howto/logging.html#custom-levels

Thoughts @eric-wieser ?

Resolving patch:
diff --git a/cocotb/log.py b/cocotb/log.py
--- a/cocotb/log.py
+++ b/cocotb/log.py
@@ -52,6 +52,10 @@
 _LINENO_CHARS   = 4  # noqa
 _FUNCNAME_CHARS = 31  # noqa
 
+# Custom log level
+logging.TRACE = 5
+logging.addLevelName(5, "TRACE")
+
 # Default log level if not overwritten by the user.
 _COCOTB_LOG_LEVEL_DEFAULT = "INFO"
 
@@ -99,7 +103,7 @@ def default_config():
     try:
         log.setLevel(level)
     except ValueError:
-        valid_levels = ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG')
+        valid_levels = ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'TRACE')
         raise ValueError("Invalid log level %r passed through the "
                          "COCOTB_LOG_LEVEL environment variable. Valid log "
                          "levels: %s" % (level, ', '.join(valid_levels)))
@@ -235,6 +239,7 @@ class SimColourLogFormatter(SimLogFormatter):
     """Log formatter to provide consistent log message handling."""
 
     loglevel2colour = {
+        logging.TRACE   :       "%s",
         logging.DEBUG   :       "%s",
         logging.INFO    :       "%s",
         logging.WARNING :       ANSI.COLOR_WARNING + "%s" + ANSI.COLOR_DEFAULT,


Test patch:
diff --git a/tests/test_cases/test_cocotb/test_logging.py b/tests/test_cases/test_cocotb/test_logging.py
--- a/tests/test_cases/test_cocotb/test_logging.py
+++ b/tests/test_cases/test_cocotb/test_logging.py
@@ -65,6 +65,11 @@ async def test_logging_default_config(dut):
         log_default_config()
         assert cocotb_log.level == logging.ERROR, cocotb_log.level
 
+        # Set custom TRACE log level
+        os.environ['COCOTB_LOG_LEVEL'] = 'TRACE'
+        log_default_config()
+        assert cocotb_log.level == logging.TRACE, cocotb_log.level
+
     finally:
         # Restore pre-test configuration
         os.environ = os_environ_prev