tuned-adm: Print log excerpt when changing profile
Print messages logged during a profile switch to stderr (this affects
the "profile" and "auto_profile" commands). By default messages with
log level ERROR and higher are printed. This can be changed using the
--loglevel command line option. Valid values are debug, info, warn,
error, console, none ('none' can be used to disable the log printing).
E.g.:
tuned-adm --loglevel info profile powersave
Log printing cannot be used when --async is used.
Resolves: rhbz#1538745
Signed-off-by: Ondřej Lysoněk <olysonek@redhat.com>
This commit is contained in:
parent
829c7de36c
commit
6c1df704ce
5 changed files with 76 additions and 2 deletions
3
TODO
3
TODO
|
|
@ -5,3 +5,6 @@
|
||||||
disconnects from DBus.
|
disconnects from DBus.
|
||||||
* Use only one timer for destroying log handlers at a time. Create a new
|
* Use only one timer for destroying log handlers at a time. Create a new
|
||||||
timer as necessary when the old timer fires.
|
timer as necessary when the old timer fires.
|
||||||
|
* Handle signals in tuned-adm so that the log_capture_finish() DBus call
|
||||||
|
is called even if we receive a signal. This may require some rewriting
|
||||||
|
of tuned-adm.
|
||||||
|
|
|
||||||
19
tuned-adm.py
19
tuned-adm.py
|
|
@ -37,6 +37,15 @@ def check_positive(value):
|
||||||
raise argparse.ArgumentTypeError("%s has to be >= 0" % value)
|
raise argparse.ArgumentTypeError("%s has to be >= 0" % value)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
def check_log_level(value):
|
||||||
|
try:
|
||||||
|
return consts.CAPTURE_LOG_LEVELS[value.lower()]
|
||||||
|
except KeyError:
|
||||||
|
levels = ", ".join(consts.CAPTURE_LOG_LEVELS.keys())
|
||||||
|
raise argparse.ArgumentTypeError(
|
||||||
|
"Invalid log level: %s. Valid log levels: %s."
|
||||||
|
% (value, levels))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
config = GlobalConfig()
|
config = GlobalConfig()
|
||||||
parser = argparse.ArgumentParser(description="Manage tuned daemon.")
|
parser = argparse.ArgumentParser(description="Manage tuned daemon.")
|
||||||
|
|
@ -44,6 +53,13 @@ if __name__ == "__main__":
|
||||||
parser.add_argument("--debug", "-d", action="store_true", help="show debug messages")
|
parser.add_argument("--debug", "-d", action="store_true", help="show debug messages")
|
||||||
parser.add_argument("--async", "-a", action="store_true", help="with dbus do not wait on commands completion and return immediately")
|
parser.add_argument("--async", "-a", action="store_true", help="with dbus do not wait on commands completion and return immediately")
|
||||||
parser.add_argument("--timeout", "-t", default = consts.ADMIN_TIMEOUT, type = check_positive, help="with sync operation use specific timeout instead of the default %d second(s)" % consts.ADMIN_TIMEOUT)
|
parser.add_argument("--timeout", "-t", default = consts.ADMIN_TIMEOUT, type = check_positive, help="with sync operation use specific timeout instead of the default %d second(s)" % consts.ADMIN_TIMEOUT)
|
||||||
|
levels = ", ".join(consts.CAPTURE_LOG_LEVELS.keys())
|
||||||
|
help = "level of log messages to capture (one of %s). Default: %s" \
|
||||||
|
% (levels, consts.CAPTURE_LOG_LEVEL)
|
||||||
|
parser.add_argument("--loglevel", "-l",
|
||||||
|
default = consts.CAPTURE_LOG_LEVEL,
|
||||||
|
type = check_log_level,
|
||||||
|
help = help)
|
||||||
|
|
||||||
subparsers = parser.add_subparsers()
|
subparsers = parser.add_subparsers()
|
||||||
|
|
||||||
|
|
@ -85,12 +101,13 @@ if __name__ == "__main__":
|
||||||
async = options.pop("async")
|
async = options.pop("async")
|
||||||
timeout = options.pop("timeout")
|
timeout = options.pop("timeout")
|
||||||
action_name = options.pop("action")
|
action_name = options.pop("action")
|
||||||
|
log_level = options.pop("loglevel")
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
dbus = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON)
|
dbus = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
admin = tuned.admin.Admin(dbus, debug, async, timeout)
|
admin = tuned.admin.Admin(dbus, debug, async, timeout, log_level)
|
||||||
|
|
||||||
result = admin.action(action_name, **options)
|
result = admin.action(action_name, **options)
|
||||||
except:
|
except:
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,12 @@ import sys
|
||||||
import errno
|
import errno
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
import logging
|
||||||
|
|
||||||
class Admin(object):
|
class Admin(object):
|
||||||
def __init__(self, dbus = True, debug = False, async = False, timeout = consts.ADMIN_TIMEOUT):
|
def __init__(self, dbus = True, debug = False, async = False,
|
||||||
|
timeout = consts.ADMIN_TIMEOUT,
|
||||||
|
log_level = logging.ERROR):
|
||||||
self._dbus = dbus
|
self._dbus = dbus
|
||||||
self._debug = debug
|
self._debug = debug
|
||||||
self._async = async
|
self._async = async
|
||||||
|
|
@ -25,6 +28,10 @@ class Admin(object):
|
||||||
self._daemon_action_result = True
|
self._daemon_action_result = True
|
||||||
self._daemon_action_errstr = ""
|
self._daemon_action_errstr = ""
|
||||||
self._controller = None
|
self._controller = None
|
||||||
|
self._log_token = None
|
||||||
|
self._log_level = log_level
|
||||||
|
# 25 seconds default DBus timeout + 5 seconds safety margin
|
||||||
|
self._log_capture_timeout = self._timeout + 25 + 5
|
||||||
if self._dbus:
|
if self._dbus:
|
||||||
self._controller = tuned.admin.DBusController(consts.DBUS_BUS, consts.DBUS_INTERFACE, consts.DBUS_OBJECT, debug)
|
self._controller = tuned.admin.DBusController(consts.DBUS_BUS, consts.DBUS_INTERFACE, consts.DBUS_OBJECT, debug)
|
||||||
try:
|
try:
|
||||||
|
|
@ -72,6 +79,8 @@ class Admin(object):
|
||||||
return False
|
return False
|
||||||
if self._dbus:
|
if self._dbus:
|
||||||
try:
|
try:
|
||||||
|
self._controller.set_on_exit_action(
|
||||||
|
self._log_capture_finish)
|
||||||
self._controller.set_action(action_dbus, *args, **kwargs)
|
self._controller.set_action(action_dbus, *args, **kwargs)
|
||||||
res = self._controller.run()
|
res = self._controller.run()
|
||||||
except TunedAdminDBusException as e:
|
except TunedAdminDBusException as e:
|
||||||
|
|
@ -218,6 +227,17 @@ class Admin(object):
|
||||||
return self._controller.exit(True)
|
return self._controller.exit(True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _log_capture_finish(self):
|
||||||
|
if self._log_token is None or self._log_token == "":
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
log_msgs = self._controller.log_capture_finish(
|
||||||
|
self._log_token)
|
||||||
|
self._log_token = None
|
||||||
|
self._error(log_msgs)
|
||||||
|
except TunedAdminDBusException as e:
|
||||||
|
self._error("Error: Failed to stop log capture. Restart the Tuned daemon to prevent a memory leak.")
|
||||||
|
|
||||||
def _action_dbus_profile(self, profiles):
|
def _action_dbus_profile(self, profiles):
|
||||||
if len(profiles) == 0:
|
if len(profiles) == 0:
|
||||||
return self._action_dbus_list()
|
return self._action_dbus_list()
|
||||||
|
|
@ -225,6 +245,10 @@ class Admin(object):
|
||||||
if profile_name == "":
|
if profile_name == "":
|
||||||
return self._controller.exit(False)
|
return self._controller.exit(False)
|
||||||
self._daemon_action_finished.clear()
|
self._daemon_action_finished.clear()
|
||||||
|
if not self._async and self._log_level is not None:
|
||||||
|
self._log_token = self._controller.log_capture_start(
|
||||||
|
self._log_level,
|
||||||
|
self._log_capture_timeout)
|
||||||
(ret, msg) = self._controller.switch_profile(profile_name)
|
(ret, msg) = self._controller.switch_profile(profile_name)
|
||||||
if self._async or not ret:
|
if self._async or not ret:
|
||||||
return self._controller.exit(self._profile_print_status(ret, msg))
|
return self._controller.exit(self._profile_print_status(ret, msg))
|
||||||
|
|
@ -266,6 +290,10 @@ class Admin(object):
|
||||||
def _action_dbus_auto_profile(self):
|
def _action_dbus_auto_profile(self):
|
||||||
profile_name = self._controller.recommend_profile()
|
profile_name = self._controller.recommend_profile()
|
||||||
self._daemon_action_finished.clear()
|
self._daemon_action_finished.clear()
|
||||||
|
if not self._async and self._log_level is not None:
|
||||||
|
self._log_token = self._controller.log_capture_start(
|
||||||
|
self._log_level,
|
||||||
|
self._log_capture_timeout)
|
||||||
(ret, msg) = self._controller.auto_profile()
|
(ret, msg) = self._controller.auto_profile()
|
||||||
if self._async or not ret:
|
if self._async or not ret:
|
||||||
return self._controller.exit(self._profile_print_status(ret, msg))
|
return self._controller.exit(self._profile_print_status(ret, msg))
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class DBusController(object):
|
||||||
self._debug = debug
|
self._debug = debug
|
||||||
self._main_loop = None
|
self._main_loop = None
|
||||||
self._action = None
|
self._action = None
|
||||||
|
self._on_exit_action = None
|
||||||
self._ret = True
|
self._ret = True
|
||||||
self._exit = False
|
self._exit = False
|
||||||
self._exception = None
|
self._exception = None
|
||||||
|
|
@ -42,12 +43,20 @@ class DBusController(object):
|
||||||
self._exit = True
|
self._exit = True
|
||||||
|
|
||||||
if self._exit:
|
if self._exit:
|
||||||
|
if self._on_exit_action is not None:
|
||||||
|
self._on_exit_action(*self._on_exit_action_args,
|
||||||
|
**self._on_exit_action_kwargs)
|
||||||
self._main_loop.quit()
|
self._main_loop.quit()
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def set_on_exit_action(self, action, *args, **kwargs):
|
||||||
|
self._on_exit_action = action
|
||||||
|
self._on_exit_action_args = args
|
||||||
|
self._on_exit_action_kwargs = kwargs
|
||||||
|
|
||||||
def set_action(self, action, *args, **kwargs):
|
def set_action(self, action, *args, **kwargs):
|
||||||
self._action = action
|
self._action = action
|
||||||
self._action_args = args
|
self._action_args = args
|
||||||
|
|
@ -96,6 +105,12 @@ class DBusController(object):
|
||||||
def profile_info(self, profile_name):
|
def profile_info(self, profile_name):
|
||||||
return self._call("profile_info", profile_name)
|
return self._call("profile_info", profile_name)
|
||||||
|
|
||||||
|
def log_capture_start(self, log_level, timeout):
|
||||||
|
return self._call("log_capture_start", log_level, timeout)
|
||||||
|
|
||||||
|
def log_capture_finish(self, token):
|
||||||
|
return self._call("log_capture_finish", token)
|
||||||
|
|
||||||
def active_profile(self):
|
def active_profile(self):
|
||||||
return self._call("active_profile")
|
return self._call("active_profile")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf"
|
GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf"
|
||||||
ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile"
|
ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile"
|
||||||
PROFILE_MODE_FILE = "/etc/tuned/profile_mode"
|
PROFILE_MODE_FILE = "/etc/tuned/profile_mode"
|
||||||
|
|
@ -113,3 +115,12 @@ ACTIVE_PROFILE_MANUAL = "manual"
|
||||||
|
|
||||||
LOG_LEVEL_CONSOLE = 60
|
LOG_LEVEL_CONSOLE = 60
|
||||||
LOG_LEVEL_CONSOLE_NAME = "CONSOLE"
|
LOG_LEVEL_CONSOLE_NAME = "CONSOLE"
|
||||||
|
CAPTURE_LOG_LEVEL = "error"
|
||||||
|
CAPTURE_LOG_LEVELS = {
|
||||||
|
"debug": logging.DEBUG,
|
||||||
|
"info": logging.INFO,
|
||||||
|
"warn": logging.WARN,
|
||||||
|
"error": logging.ERROR,
|
||||||
|
"console": LOG_LEVEL_CONSOLE,
|
||||||
|
"none": None,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue