[PATCH v2 1/2] tuna: Add logging infrastructure to tuna-cmd
by Leah Leshchinsky
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 <lleshchi(a)redhat.com>
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
1 year, 6 months
[PATCH 1/2] tuna: Add logging infrastructure to tuna-cmd
by Leah Leshchinsky
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 the console and the log file within
the created directory.
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 <lleshchi(a)redhat.com>
diff --git a/tuna-cmd.py b/tuna-cmd.py
index ac21481df554..cb19184ba127 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("Debugging is up and running!")
+ 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 is up and running!")
if o in ("-a", "--config_file_apply"):
apply_config(a)
elif o in ("-l", "--config_file_list"):
--
2.27.0
1 year, 6 months