From 85330a8ab1afec5370676e7c3d753a4528f24e6f Mon Sep 17 00:00:00 2001 From: Leah Leshchinsky Date: Tue, 10 May 2022 11:59:07 -0400 Subject: [PATCH 1/2] tuna: Add logging infrastructure to tuna-cmd Currently, tuna does not have an easy way for developers and maintainers to access necessary information about the state of the program. Add logging infrastructure that allows the user to specify, at the command line, what level of logging to print from the following levels: (notset, debug, info, warning, error, critical). Levels may also be specified numerically, ranging from 0-5. A directory will be created with the current date and test run. Logging statements will print to a log file within the created directory, and can be specified with the '-L' and '--logging' flags. The '-D' and '--debug' flags will print all debug information to the console. Logging of other files outside of tuna-cmd.py can be implemented by importing the logging directory and adding the necessary logging statments. Signed-off-by: Leah Leshchinsky Signed-off-by: John Kacur diff --git a/tuna-cmd.py b/tuna-cmd.py index ac21481df554..57b62298c48a 100755 --- a/tuna-cmd.py +++ b/tuna-cmd.py @@ -29,6 +29,50 @@ import ethtool import tuna.tuna_sched as tuna_sched import procfs from tuna import tuna, sysfs +import logging +import time + +def get_loglevel(level): + if level.isdigit() and int(level) in range(0,5): + # logging built-in module levels: + # 0 - NOTSET + # 10 - DEBUG + # 20 - INFO, + # 30 - WARNING + # 40 - ERROR + return int(level) * 10 + level_str = level.upper() + if level_str == "CRITICAL": + raise ValueError("CRITICAL level is not supported by tuna") + return level_str + +def setup_logging(logger_name): + + logger = logging.getLogger(logger_name) + logger.setLevel(logging.DEBUG) + logger.propagate = False + return logger + +def add_handler(loglevel, tofile=False): + + formatter = logging.Formatter('[%(levelname)s] %(message)s') + + if tofile: + lognum = 1 + date = time.strftime("%Y%m%d") + while os.path.exists("tuna-{}-{}".format(date, lognum)): + lognum += 1 + + path = "tuna-{}-{}/log/Log".format(date,lognum) + os.makedirs(os.path.dirname(path), exist_ok=True, mode=0o777) + handler = logging.FileHandler(path) + else: + handler = logging.StreamHandler(sys.stderr) + + handler.setFormatter(formatter) + handler.setLevel(loglevel) + + return handler try: import inet_diag @@ -61,6 +105,7 @@ def usage(): _('Operation will affect children threads'))) print(fmt % ('-d, --disable_perf', _('Explicitly disable usage of perf in GUI for process view'))) + print(fmt % ('-D, --debug', _('Print DEBUG level logging details to console'))) print(fmt % ('-f, --filter', _('Display filter the selected entities'))) print(fmt % ('-i, --isolate', _('Move all allowed threads and IRQs away from %(cpulist)s') % @@ -69,6 +114,8 @@ def usage(): {"cpulist": _('CPU-LIST')})) print(fmt % ('-K, --no_kthreads', _('Operations will not affect kernel threads'))) + print(fmt % ('-L, --logging', + _('Log application details to log file for given LOG-LEVEL'))) print(fmt % ('-m, --move', _('Move selected entities to %(cpulist)s') % {"cpulist": _('CPU-LIST')})) print(fmt % ('-N, --nohz_full', @@ -490,14 +537,14 @@ def main(): i18n_init() try: - short = "a:c:dCfgGhiIKlmNp:PQq:r:R:s:S:t:UvWx" + short = "a:c:dDCfgGhiIKlmNp:PQq:r:R:s:S:t:UvWxL:" long = ["cpus=", "affect_children", "filter", "gui", "help", "isolate", "include", "no_kthreads", "move", "nohz_full", "show_sockets", "priority=", "show_threads", "show_irqs", "irqs=", "save=", "sockets=", "threads=", "no_uthreads", "version", "what_is", "spread", "cgroup", "config_file_apply=", - "config_file_list", "run=", "refresh=", "disable_perf"] + "config_file_list", "run=", "refresh=", "disable_perf", "logging=", "debug"] if have_inet_diag: short += "n" long.append("show_sockets") @@ -512,8 +559,10 @@ def main(): uthreads = True cgroups = False cpu_list = None + debug = False irq_list = None irq_list_str = None + log = False rtprio = None policy = None thread_list = [] @@ -529,6 +578,30 @@ def main(): if o in ("-h", "--help"): usage() return + if o in ("-D", "--debug"): + if debug: + my_logger.warning("Debugging already set") + continue + debug = True + if not log: + my_logger = setup_logging("my_logger") + my_logger.addHandler(add_handler("DEBUG", tofile=False)) + my_logger.info("Debug option set") + if o in ("-L", "--logging"): + if log: + my_logger.warning("Logging already set") + continue + log = True + loglevel = get_loglevel(a) + if not debug: + my_logger = setup_logging("my_logger") + try: + my_logger.addHandler(add_handler(loglevel, tofile=True)) + except ValueError as e: + print(e, "tuna: --logging requires valid logging level\n") + print("Valid log levels: NOTSET, DEBUG, INFO, WARNING, ERROR") + print("Log levels may be specified numerically (0-4)") + my_logger.info("Logging option set") if o in ("-a", "--config_file_apply"): apply_config(a) elif o in ("-l", "--config_file_list"): -- 2.27.0