From: "Juraj Linkeš" <juraj.linkes@pantheon.tech>
To: thomas@monjalon.net, david.marchand@redhat.com,
Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu,
lijuan.tu@intel.com
Cc: dev@dpdk.org, "Juraj Linkeš" <juraj.linkes@pantheon.tech>
Subject: [RFC PATCH v1 09/15] dts: merge DTS framework/logger.py to DPDK
Date: Wed, 6 Apr 2022 14:56:00 +0000 [thread overview]
Message-ID: <20220406145606.2913834-10-juraj.linkes@pantheon.tech> (raw)
In-Reply-To: <20220406145606.2913834-1-juraj.linkes@pantheon.tech>
---
dts/framework/logger.py | 474 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 474 insertions(+)
create mode 100644 dts/framework/logger.py
diff --git a/dts/framework/logger.py b/dts/framework/logger.py
new file mode 100644
index 0000000000..576a51dcf3
--- /dev/null
+++ b/dts/framework/logger.py
@@ -0,0 +1,474 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import inspect
+import logging
+import os
+import re
+import sys
+
+from .settings import DTS_PARALLEL_SETTING, FOLDERS, LOG_NAME_SEP, load_global_setting
+from .utils import RED
+
+"""
+DTS logger module with several log level. DTS framework and TestSuite log
+will saved into different log files.
+"""
+verbose = False
+
+logging.DTS_DUT_CMD = logging.INFO + 1
+logging.DTS_DUT_OUTPUT = logging.DEBUG + 1
+logging.DTS_DUT_RESULT = logging.WARNING + 1
+
+logging.DTS_TESTER_CMD = logging.INFO + 2
+logging.DTS_TESTER_OUTPUT = logging.DEBUG + 2
+logging.DTS_TESTER_RESULT = logging.WARNING + 2
+
+logging.SUITE_DUT_CMD = logging.INFO + 3
+logging.SUITE_DUT_OUTPUT = logging.DEBUG + 3
+
+logging.SUITE_TESTER_CMD = logging.INFO + 4
+logging.SUITE_TESTER_OUTPUT = logging.DEBUG + 4
+
+logging.DTS_VIRTDUT_CMD = logging.INFO + 6
+logging.DTS_VIRTDUT_OUTPUT = logging.DEBUG + 6
+
+logging.DTS_PKTGEN_CMD = logging.INFO + 7
+logging.DTS_PKTGEN_OUTPUT = logging.DEBUG + 7
+
+logging.addLevelName(logging.DTS_DUT_CMD, "DTS_DUT_CMD")
+logging.addLevelName(logging.DTS_DUT_OUTPUT, "DTS_DUT_OUTPUT")
+logging.addLevelName(logging.DTS_DUT_RESULT, "DTS_DUT_RESULT")
+
+logging.addLevelName(logging.DTS_TESTER_CMD, "DTS_TESTER_CMD")
+logging.addLevelName(logging.DTS_TESTER_OUTPUT, "DTS_TESTER_OUTPUT")
+logging.addLevelName(logging.DTS_TESTER_RESULT, "DTS_TESTER_RESULT")
+
+logging.addLevelName(logging.DTS_VIRTDUT_CMD, "VIRTDUT_CMD")
+logging.addLevelName(logging.DTS_VIRTDUT_OUTPUT, "VIRTDUT_OUTPUT")
+
+logging.addLevelName(logging.SUITE_DUT_CMD, "SUITE_DUT_CMD")
+logging.addLevelName(logging.SUITE_DUT_OUTPUT, "SUITE_DUT_OUTPUT")
+
+logging.addLevelName(logging.SUITE_TESTER_CMD, "SUITE_TESTER_CMD")
+logging.addLevelName(logging.SUITE_TESTER_OUTPUT, "SUITE_TESTER_OUTPUT")
+
+logging.addLevelName(logging.DTS_PKTGEN_CMD, "DTS_PKTGEN_CMD")
+logging.addLevelName(logging.DTS_PKTGEN_OUTPUT, "DTS_PKTGEN_OUTPUT")
+
+date_fmt = "%d/%m/%Y %H:%M:%S"
+RESET_COLOR = "\033[0m"
+stream_fmt = "%(color)s%(name)30s: %(message)s" + RESET_COLOR
+log_dir = None
+
+# List for saving all using loggers
+global Loggers
+Loggers = []
+
+
+def set_verbose():
+ global verbose
+ verbose = True
+
+
+class BaseLoggerAdapter(logging.LoggerAdapter):
+ """
+ Upper layer of original logging module.
+ """
+
+ def dts_dut_cmd(self, msg, *args, **kwargs):
+ self.log(logging.DTS_DUT_CMD, msg, *args, **kwargs)
+
+ def dts_dut_output(self, msg, *args, **kwargs):
+ self.log(logging.DTS_DUT_OUTPUT, msg, *args, **kwargs)
+
+ def dts_dut_result(self, msg, *args, **kwargs):
+ self.log(logging.DTS_DUT_RESULT, msg, *args, **kwargs)
+
+ def dts_tester_cmd(self, msg, *args, **kwargs):
+ self.log(logging.DTS_TESTER_CMD, msg, *args, **kwargs)
+
+ def dts_tester_output(self, msg, *args, **kwargs):
+ self.log(logging.DTS_TESTER_CMD, msg, *args, **kwargs)
+
+ def dts_tester_result(self, msg, *args, **kwargs):
+ self.log(logging.DTS_TESTER_RESULT, msg, *args, **kwargs)
+
+ def suite_dut_cmd(self, msg, *args, **kwargs):
+ self.log(logging.SUITE_DUT_CMD, msg, *args, **kwargs)
+
+ def suite_dut_output(self, msg, *args, **kwargs):
+ self.log(logging.SUITE_DUT_OUTPUT, msg, *args, **kwargs)
+
+ def suite_tester_cmd(self, msg, *args, **kwargs):
+ self.log(logging.SUITE_TESTER_CMD, msg, *args, **kwargs)
+
+ def suite_tester_output(self, msg, *args, **kwargs):
+ self.log(logging.SUITE_TESTER_OUTPUT, msg, *args, **kwargs)
+
+ def dts_virtdut_cmd(self, msg, *args, **kwargs):
+ self.log(logging.DTS_VIRTDUT_CMD, msg, *args, **kwargs)
+
+ def dts_virtdut_output(self, msg, *args, **kwargs):
+ self.log(logging.DTS_VIRTDUT_OUTPUT, msg, *args, **kwargs)
+
+ def dts_pktgen_cmd(self, msg, *args, **kwargs):
+ self.log(logging.DTS_PKTGEN_CMD, msg, *args, **kwargs)
+
+ def dts_pktgen_output(self, msg, *args, **kwargs):
+ self.log(logging.DTS_PKTGEN_OUTPUT, msg, *args, **kwargs)
+
+
+class ColorHandler(logging.StreamHandler):
+ """
+ Color of DTS log format.
+ """
+
+ LEVEL_COLORS = {
+ logging.DEBUG: "", # SYSTEM
+ logging.DTS_DUT_OUTPUT: "\033[00;37m", # WHITE
+ logging.DTS_TESTER_OUTPUT: "\033[00;37m", # WHITE
+ logging.SUITE_DUT_OUTPUT: "\033[00;37m", # WHITE
+ logging.SUITE_TESTER_OUTPUT: "\033[00;37m", # WHITE
+ logging.INFO: "\033[00;36m", # CYAN
+ logging.DTS_DUT_CMD: "", # SYSTEM
+ logging.DTS_TESTER_CMD: "", # SYSTEM
+ logging.SUITE_DUT_CMD: "", # SYSTEM
+ logging.SUITE_TESTER_CMD: "", # SYSTEM
+ logging.DTS_PKTGEN_CMD: "", # SYSTEM
+ logging.DTS_PKTGEN_OUTPUT: "", # SYSTEM
+ logging.DTS_VIRTDUT_CMD: "", # SYSTEM
+ logging.DTS_VIRTDUT_OUTPUT: "", # SYSTEM
+ logging.WARN: "\033[01;33m", # BOLD YELLOW
+ logging.DTS_DUT_RESULT: "\033[01;34m", # BOLD BLUE
+ logging.DTS_TESTER_RESULT: "\033[01;34m", # BOLD BLUE
+ logging.ERROR: "\033[01;31m", # BOLD RED
+ logging.CRITICAL: "\033[01;31m", # BOLD RED
+ }
+
+ def format(self, record):
+ record.__dict__["color"] = self.LEVEL_COLORS[record.levelno]
+ return logging.StreamHandler.format(self, record)
+
+
+class DTSLOG(BaseLoggerAdapter):
+ """
+ DTS log class for framework and testsuite.
+ """
+
+ def __init__(self, logger, crb="suite"):
+ global log_dir
+ filename = inspect.stack()[1][1][:-3]
+
+ self.error_lvl = logging.ERROR
+ self.warn_lvl = logging.WARNING
+ self.info_lvl = logging.INFO
+ self.debug_lvl = logging.DEBUG
+
+ if log_dir is None:
+ self.log_path = os.getcwd() + "/../" + FOLDERS["Output"]
+ else:
+ self.log_path = (
+ log_dir # log dir should contain tag/crb global value and mod in dts
+ )
+ self.dts_log = "dts.log"
+
+ self.logger = logger
+ self.logger.setLevel(logging.DEBUG)
+
+ self.crb = crb
+ super(DTSLOG, self).__init__(self.logger, dict(crb=self.crb))
+
+ self.fh = None
+ self.ch = None
+
+ # add default log file
+ fh = logging.FileHandler(self.log_path + "/" + self.dts_log)
+ ch = ColorHandler()
+ self.__log_handler(fh, ch)
+
+ def __log_handler(self, fh, ch):
+ """
+ Config stream handler and file handler.
+ """
+ if load_global_setting(DTS_PARALLEL_SETTING) == "yes":
+ message_fmt = "%(asctime)s %(name)30s %(threadName)s: %(message)s"
+ else:
+ message_fmt = "%(asctime)s %(name)30s: %(message)s"
+
+ fh.setFormatter(logging.Formatter(message_fmt, date_fmt))
+ ch.setFormatter(logging.Formatter(stream_fmt, date_fmt))
+
+ fh.setLevel(logging.DEBUG) # file handler default level
+ global verbose
+ if verbose is True:
+ ch.setLevel(logging.DEBUG)
+ else:
+ ch.setLevel(logging.INFO) # console handler default level
+
+ self.logger.addHandler(fh)
+ self.logger.addHandler(ch)
+
+ if self.fh is not None:
+ self.logger.removeHandler(self.fh)
+ if self.ch is not None:
+ self.logger.removeHandler(self.ch)
+
+ self.fh = fh
+ self.ch = ch
+
+ def warning(self, message):
+ """
+ DTS warnning level log function.
+ """
+ self.logger.log(self.warn_lvl, message)
+
+ def info(self, message):
+ """
+ DTS information level log function.
+ """
+ self.logger.log(self.info_lvl, message)
+
+ def error(self, message):
+ """
+ DTS error level log function.
+ """
+ self.logger.log(self.error_lvl, message)
+
+ def debug(self, message):
+ """
+ DTS debug level log function.
+ """
+ self.logger.log(self.debug_lvl, message)
+
+ def set_logfile_path(self, path):
+ """
+ Configure the log file path.
+ """
+ self.log_path = path
+
+ def set_stream_level(self, lvl):
+ """
+ Configure the stream level, logger level >= stream level will be
+ output on the screen.
+ """
+ self.ch.setLevel(lvl)
+
+ def set_logfile_level(self, lvl):
+ """
+ Configure the file handler level, logger level >= logfile level will
+ be saved into log file.
+ """
+ self.fh.setLevel(lvl)
+
+ def config_execution(self, crb):
+ """
+ Reconfigure stream&logfile level and reset info,debug,warn level.
+ """
+ log_file = self.log_path + "/" + self.dts_log
+ fh = logging.FileHandler(log_file)
+ ch = ColorHandler()
+ self.__log_handler(fh, ch)
+
+ if crb.startswith("dut"):
+ self.info_lvl = logging.DTS_DUT_CMD
+ self.debug_lvl = logging.DTS_DUT_OUTPUT
+ self.warn_lvl = logging.DTS_DUT_RESULT
+ elif crb.startswith("tester"):
+ self.info_lvl = logging.DTS_TESTER_CMD
+ self.debug_lvl = logging.DTS_TESTER_OUTPUT
+ self.warn_lvl = logging.DTS_TESTER_RESULT
+ elif crb.startswith("pktgen"):
+ self.info_lvl = logging.DTS_PKTGEN_CMD
+ self.debug_lvl = logging.DTS_PKTGEN_OUTPUT
+ elif crb.startswith("virtdut"):
+ self.info_lvl = logging.DTS_VIRTDUT_CMD
+ self.debug_lvl = logging.DTS_VIRTDUT_OUTPUT
+ else:
+ self.error_lvl = logging.ERROR
+ self.warn_lvl = logging.WARNING
+ self.info_lvl = logging.INFO
+ self.debug_lvl = logging.DEBUG
+
+ def config_suite(self, suitename, crb=None):
+ """
+ Reconfigure stream&logfile level and reset info,debug level.
+ """
+ log_file = self.log_path + "/" + suitename + ".log"
+ fh = logging.FileHandler(log_file)
+ ch = ColorHandler()
+
+ # exit first
+ self.logger_exit()
+
+ # then add handler
+ self.__log_handler(fh, ch)
+
+ if crb == "dut":
+ self.info_lvl = logging.SUITE_DUT_CMD
+ self.debug_lvl = logging.SUITE_DUT_OUTPUT
+ elif crb == "tester":
+ self.info_lvl = logging.SUITE_TESTER_CMD
+ self.debug_lvl = logging.SUITE_TESTER_OUTPUT
+ elif crb == "pktgen":
+ self.info_lvl = logging.DTS_PKTGEN_CMD
+ self.debug_lvl = logging.DTS_PKTGEN_OUTPUT
+ elif crb == "virtdut":
+ self.info_lvl = logging.DTS_VIRTDUT_CMD
+ self.debug_lvl = logging.DTS_VIRTDUT_OUTPUT
+
+ def logger_exit(self):
+ """
+ Remove stream handler and logfile handler.
+ """
+ if self.fh is not None:
+ self.logger.removeHandler(self.fh)
+ if self.ch is not None:
+ self.logger.removeHandler(self.ch)
+
+
+def getLogger(name, crb="suite"):
+ """
+ Get logger handler and if there's no handler for specified CRB will create one.
+ """
+ global Loggers
+ # return saved logger
+ for logger in Loggers:
+ if logger["name"] == name and logger["crb"] == crb:
+ return logger["logger"]
+
+ # return new logger
+ logger = DTSLOG(logging.getLogger(name), crb)
+ Loggers.append({"logger": logger, "name": name, "crb": crb})
+ return logger
+
+
+_TESTSUITE_NAME_FORMAT_PATTERN = r"TEST SUITE : (.*)"
+_TESTSUITE_ENDED_FORMAT_PATTERN = r"TEST SUITE ENDED: (.*)"
+_TESTCASE_NAME_FORMAT_PATTERN = r"Test Case (.*) Begin"
+_TESTCASE_RESULT_FORMAT_PATTERN = r"Test Case (.*) Result (.*):"
+
+
+class LogParser(object):
+ """
+ Module for parsing saved log file, will implement later.
+ """
+
+ def __init__(self, log_path):
+ self.log_path = log_path
+
+ try:
+ self.log_handler = open(self.log_path, "r")
+ except:
+ print(RED("Failed to logfile %s" % log_path))
+ return None
+
+ self.suite_pattern = re.compile(_TESTSUITE_NAME_FORMAT_PATTERN)
+ self.end_pattern = re.compile(_TESTSUITE_ENDED_FORMAT_PATTERN)
+ self.case_pattern = re.compile(_TESTCASE_NAME_FORMAT_PATTERN)
+ self.result_pattern = re.compile(_TESTCASE_RESULT_FORMAT_PATTERN)
+
+ self.loglist = self.parse_logfile()
+ self.log_handler.close()
+
+ def locate_suite(self, suite_name=None):
+ begin = 0
+ end = len(self.loglist)
+ for line in self.loglist:
+ m = self.suite_pattern.match(list(line.values())[0])
+ if m:
+ if suite_name is None:
+ begin = self.loglist.index(line)
+ elif suite_name == m.group(1):
+ begin = self.loglist.index(line)
+
+ for line in self.loglist[begin:]:
+ m = self.end_pattern.match(list(line.values())[0])
+ if m:
+ if suite_name is None:
+ end = self.loglist.index(line)
+ elif suite_name == m.group(1):
+ end = self.loglist.index(line)
+
+ return self.loglist[begin : end + 1]
+
+ def locate_case(self, case_name=None):
+ begin = 0
+ end = len(self.loglist)
+ for line in self.loglist:
+ # only handle case log
+ m = self.case_pattern.match(list(line.values())[0])
+ if m:
+ # not determine case will start from beginning
+ if case_name is None:
+ begin = self.loglist.index(line)
+ # start from the determined case
+ elif case_name == m.group(1):
+ begin = self.loglist.index(line)
+
+ for line in self.loglist[begin:]:
+ m = self.result_pattern.match(list(line.values())[0])
+ if m:
+ # not determine case will stop to the end
+ if case_name is None:
+ end = self.loglist.index(line)
+ # stop to the determined case
+ elif case_name == m.group(1):
+ end = self.loglist.index(line)
+
+ return self.loglist[begin : end + 1]
+
+ def __dict_log(self, lvl_name, msg):
+ tmp = {}
+ if lvl_name != "":
+ tmp[lvl_name] = msg
+ return tmp
+
+ def parse_logfile(self):
+ loglist = []
+
+ out_type = "DTS_DUT_OUTPUT"
+ for line in self.log_handler:
+ tmp = {}
+ line = line.replace("\n", "")
+ line = line.replace("^M", "")
+ m = re.match("(\d{2}/\d{2}/\d{4}) (\d{2}:\d{2}:\d{2}) (.{20}): (.*)", line)
+ if m:
+ lvl_name = m.group(3).strip()
+ tmp = self.__dict_log(lvl_name, m.group(4))
+ if "OUTPUT" in lvl_name:
+ out_type = lvl_name
+ else:
+ tmp[out_type] = line
+
+ loglist.append(tmp)
+
+ return loglist
--
2.20.1
next prev parent reply other threads:[~2022-04-06 14:57 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-06 14:55 [RFC PATCH v1 00/15] merge DTS core files " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 01/15] dts: merge DTS dep/tclclient.tgz " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 02/15] dts: merge DTS dep/tgen.tgz " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 03/15] dts: merge DTS dts " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 04/15] dts: merge DTS framework/__init__.py " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 05/15] dts: merge DTS framework/asan_test.py " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 06/15] dts: merge DTS framework/checkCase.py " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 07/15] dts: merge DTS framework/dts.py " Juraj Linkeš
2022-04-06 14:55 ` [RFC PATCH v1 08/15] dts: merge DTS framework/exception.py " Juraj Linkeš
2022-04-06 14:56 ` Juraj Linkeš [this message]
2022-04-06 14:56 ` [RFC PATCH v1 10/15] dts: merge DTS framework/packet.py " Juraj Linkeš
2022-04-06 14:56 ` [RFC PATCH v1 11/15] dts: merge DTS framework/project_dpdk.py " Juraj Linkeš
2022-04-06 14:56 ` [RFC PATCH v1 12/15] dts: merge DTS framework/serializer.py " Juraj Linkeš
2022-04-06 14:56 ` [RFC PATCH v1 13/15] dts: merge DTS framework/utils.py " Juraj Linkeš
2022-04-06 14:56 ` [RFC PATCH v1 14/15] dts: merge DTS main.py " Juraj Linkeš
2022-04-06 14:56 ` [RFC PATCH v1 15/15] dts: merge DTS version.py " Juraj Linkeš
2022-04-07 5:04 ` [RFC PATCH v1 00/15] merge DTS core files " Jerin Jacob
2022-04-07 7:33 ` Thomas Monjalon
2022-04-11 7:41 ` Juraj Linkeš
2022-04-11 17:55 ` Honnappa Nagarahalli
2022-04-11 18:20 ` Owen Hilyard
2022-04-11 19:06 ` Honnappa Nagarahalli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220406145606.2913834-10-juraj.linkes@pantheon.tech \
--to=juraj.linkes@pantheon.tech \
--cc=Honnappa.Nagarahalli@arm.com \
--cc=david.marchand@redhat.com \
--cc=dev@dpdk.org \
--cc=lijuan.tu@intel.com \
--cc=ohilyard@iol.unh.edu \
--cc=thomas@monjalon.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).