[3/5] msg: Add a bb.warnonce() log method

Message ID 20220216113158.2899964-3-richard.purdie@linuxfoundation.org
State New
Headers show
Series [1/5] data_smart: Fix overrides file/line message additions | expand

Commit Message

Richard Purdie Feb. 16, 2022, 11:31 a.m. UTC
This adds a log level and logging function call to use it where the
warning will only be displayed once, regardless of how many times the
message is logged.

This has to be done either in the cooker or on the UI side. I've opted
for the UI side since display control is really a UI issue but it uses
a common library filter function to enable it which can be reused
elsewhere.

The knotty message displayed as the build summary is tweaked to
make sense when the numbers won't match since it will still count
the number of times it was logged and this is probably helpful
for debugging in some cases so I've deliberately left it that way.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/__init__.py  |  6 ++++++
 lib/bb/msg.py       | 15 +++++++++++++++
 lib/bb/ui/knotty.py | 17 ++++++++++-------
 3 files changed, 31 insertions(+), 7 deletions(-)

Patch

diff --git a/lib/bb/__init__.py b/lib/bb/__init__.py
index e01b8d5256..4b6ad5cbc8 100644
--- a/lib/bb/__init__.py
+++ b/lib/bb/__init__.py
@@ -71,6 +71,9 @@  class BBLoggerMixin(object):
     def verbnote(self, msg, *args, **kwargs):
         return self.log(logging.INFO + 2, msg, *args, **kwargs)
 
+    def warnonce(self, msg, *args, **kwargs):
+        return self.log(logging.WARNING - 1, msg, *args, **kwargs)
+
 Logger = logging.getLoggerClass()
 class BBLogger(Logger, BBLoggerMixin):
     def __init__(self, name, *args, **kwargs):
@@ -157,6 +160,9 @@  def verbnote(*args):
 def warn(*args):
     mainlogger.warning(''.join(args))
 
+def warnonce(*args):
+    mainlogger.warnonce(''.join(args))
+
 def error(*args, **kwargs):
     mainlogger.error(''.join(args), extra=kwargs)
 
diff --git a/lib/bb/msg.py b/lib/bb/msg.py
index 291b38ff7f..ae079c4596 100644
--- a/lib/bb/msg.py
+++ b/lib/bb/msg.py
@@ -31,6 +31,7 @@  class BBLogFormatter(logging.Formatter):
     VERBNOTE = logging.INFO + 2
     ERROR = logging.ERROR
     WARNING = logging.WARNING
+    WARNONCE = logging.WARNING - 1
     CRITICAL = logging.CRITICAL
 
     levelnames = {
@@ -42,6 +43,7 @@  class BBLogFormatter(logging.Formatter):
         PLAIN  : '',
         VERBNOTE: 'NOTE',
         WARNING : 'WARNING',
+        WARNONCE : 'WARNING',
         ERROR   : 'ERROR',
         CRITICAL: 'ERROR',
     }
@@ -58,6 +60,7 @@  class BBLogFormatter(logging.Formatter):
         PLAIN   : BASECOLOR,
         VERBNOTE: BASECOLOR,
         WARNING : YELLOW,
+        WARNONCE : YELLOW,
         ERROR   : RED,
         CRITICAL: RED,
     }
@@ -121,6 +124,18 @@  class BBLogFilter(object):
             return True
         return False
 
+class LogFilterWarnOnce(logging.Filter):
+    def __init__(self):
+        self.seen_warnings = set()
+
+    def filter(self, record):
+        msg = record.msg
+        if record.levelno == bb.msg.BBLogFormatter.WARNONCE:
+            if record.msg in self.seen_warnings:
+                return False
+            self.seen_warnings.add(record.msg)
+        return True
+
 class LogFilterGEQLevel(logging.Filter):
     def __init__(self, level):
         self.strlevel = str(level)
diff --git a/lib/bb/ui/knotty.py b/lib/bb/ui/knotty.py
index 484545a684..1c46ec843b 100644
--- a/lib/bb/ui/knotty.py
+++ b/lib/bb/ui/knotty.py
@@ -418,7 +418,7 @@  def main(server, eventHandler, params, tf = TerminalFilter):
                 "formatter": "BitBake.consoleFormatter",
                 "level": console_loglevel,
                 "stream": "ext://sys.stdout",
-                "filters": ["BitBake.stdoutFilter"],
+                "filters": ["BitBake.warnonceFilter", "BitBake.stdoutFilter"],
                 ".": {
                     "is_console": True,
                 },
@@ -428,7 +428,7 @@  def main(server, eventHandler, params, tf = TerminalFilter):
                 "formatter": "BitBake.consoleFormatter",
                 "level": loglevel,
                 "stream": "ext://sys.stderr",
-                "filters": ["BitBake.stderrFilter"],
+                "filters": ["BitBake.warnonceFilter", "BitBake.stderrFilter"],
                 ".": {
                     "is_console": True,
                 },
@@ -443,7 +443,7 @@  def main(server, eventHandler, params, tf = TerminalFilter):
                 "formatter": "BitBake.consoleFormatter",
                 "level": 1,
                 "stream": "ext://sys.stdout",
-                "filters": ["BitBake.verbconsoleFilter"],
+                "filters": ["BitBake.warnonceFilter", "BitBake.verbconsoleFilter"],
                 ".": {
                     "is_console": True,
                 },
@@ -476,6 +476,9 @@  def main(server, eventHandler, params, tf = TerminalFilter):
                 "()": "bb.msg.LogFilterLTLevel",
                 "level": console_loglevel
             },
+            "BitBake.warnonceFilter": {
+                "()": "bb.msg.LogFilterWarnOnce",
+            },
         },
         "loggers": {
             "BitBake": {
@@ -661,10 +664,10 @@  def main(server, eventHandler, params, tf = TerminalFilter):
                         continue
 
                     # Prefix task messages with recipe/task
-                    if event.taskpid in helper.pidmap and event.levelno != bb.msg.BBLogFormatter.PLAIN:
+                    if event.taskpid in helper.pidmap and event.levelno != bb.msg.BBLogFormatter.PLAIN and event.levelno != bb.msg.BBLogFormatter.WARNONCE:
                         taskinfo = helper.running_tasks[helper.pidmap[event.taskpid]]
                         event.msg = taskinfo['title'] + ': ' + event.msg
-                if hasattr(event, 'fn'):
+                if hasattr(event, 'fn') and event.levelno != bb.msg.BBLogFormatter.WARNONCE:
                     event.msg = event.fn + ': ' + event.msg
                 logging.getLogger(event.name).handle(event)
                 continue
@@ -875,8 +878,8 @@  def main(server, eventHandler, params, tf = TerminalFilter):
             for failure in taskfailures:
                 summary += "\n  %s" % failure
         if warnings:
-            summary += pluralise("\nSummary: There was %s WARNING message shown.",
-                                 "\nSummary: There were %s WARNING messages shown.", warnings)
+            summary += pluralise("\nSummary: There was %s WARNING message.",
+                                 "\nSummary: There were %s WARNING messages.", warnings)
         if return_value and errors:
             summary += pluralise("\nSummary: There was %s ERROR message shown, returning a non-zero exit code.",
                                  "\nSummary: There were %s ERROR messages shown, returning a non-zero exit code.", errors)