diff --git a/openstackclient/shell.py b/openstackclient/shell.py index dfec40a..659bbee 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -25,6 +25,7 @@ from cliff import app from cliff import command from cliff import complete from cliff import help +from oslo_utils import importutils from oslo_utils import strutils import openstackclient @@ -37,6 +38,8 @@ from openstackclient.common import utils from os_client_config import config as cloud_config +osprofiler_profiler = importutils.try_import("osprofiler.profiler") + DEFAULT_DOMAIN = 'default' @@ -101,6 +104,8 @@ class OpenStackShell(app.App): self.client_manager = None self.command_options = None + self.do_profile = False + def configure_logging(self): """Configure logging for the app.""" self.log_configurator = logs.LogConfigurator(self.options) @@ -125,6 +130,39 @@ class OpenStackShell(app.App): finally: self.log.info("END return value: %s", ret_val) + def init_profile(self): + self.do_profile = osprofiler_profiler and self.options.profile + if self.do_profile: + osprofiler_profiler.init(self.options.profile) + + def close_profile(self): + if self.do_profile: + trace_id = osprofiler_profiler.get().get_base_id() + + # NOTE(dbelova): let's use warning log level to see these messages + # printed. In fact we can define custom log level here with value + # bigger than most big default one (CRITICAL) or something like + # that (PROFILE = 60 for instance), but not sure we need it here. + self.log.warning("Trace ID: %s" % trace_id) + self.log.warning("To display trace use next command:\n" + "osprofiler trace show --html %s " % trace_id) + + def run_subcommand(self, argv): + self.init_profile() + try: + ret_value = super(OpenStackShell, self).run_subcommand(argv) + finally: + self.close_profile() + return ret_value + + def interact(self): + self.init_profile() + try: + ret_value = super(OpenStackShell, self).run_subcommand() + finally: + self.close_profile() + return ret_value + def build_option_parser(self, description, version): parser = super(OpenStackShell, self).build_option_parser( description, @@ -190,6 +228,19 @@ class OpenStackShell(app.App): help="Print API call timing info", ) + # osprofiler HMAC key argument + if osprofiler_profiler: + parser.add_argument('--profile', + metavar='hmac-key', + help='HMAC key to use for encrypting context ' + 'data for performance profiling of operation. ' + 'This key should be the value of one of the ' + 'HMAC keys configured in osprofiler ' + 'middleware in the projects user would like ' + 'to profile. It needs to be specified in ' + 'configuration files of the required ' + 'projects.') + return clientmanager.build_plugin_option_parser(parser) def initialize_app(self, argv): diff --git a/openstackclient/tests/test_shell.py b/openstackclient/tests/test_shell.py index 4a8968c..ea3c6fe 100644 --- a/openstackclient/tests/test_shell.py +++ b/openstackclient/tests/test_shell.py @@ -109,6 +109,7 @@ global_options = { '--os-default-domain': (DEFAULT_DOMAIN_NAME, True, True), '--os-cacert': ('/dev/null', True, True), '--timing': (True, True, False), + '--profile': ('SECRET_KEY', True, False), '--os-interface': (DEFAULT_INTERFACE, True, True) } diff --git a/test-requirements.txt b/test-requirements.txt index 8a37903..9c93b11 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -16,6 +16,7 @@ os-testr>=0.4.1 # Apache-2.0 testrepository>=0.0.18 # Apache-2.0/BSD testtools>=1.4.0 # MIT tempest-lib>=0.14.0 # Apache-2.0 +osprofiler>=1.1.0 # Apache-2.0 # Install these to generate sphinx autodocs python-barbicanclient>=3.3.0 # Apache-2.0