diff --git a/src/azure-cli-core/azure/cli/core/commands/__init__.py b/src/azure-cli-core/azure/cli/core/commands/__init__.py index 4fd563a6e98..d67814eaf70 100644 --- a/src/azure-cli-core/azure/cli/core/commands/__init__.py +++ b/src/azure-cli-core/azure/cli/core/commands/__init__.py @@ -36,7 +36,6 @@ ['id_part', 'completer', 'validator', 'options_list', 'configured_default', 'arg_group', 'arg_type'] \ + CLI_COMMON_KWARGS + ARGPARSE_SUPPORTED_KWARGS - CONFIRM_PARAM_NAME = 'yes' # 1 hour in milliseconds @@ -200,18 +199,22 @@ class AzCliCommandInvoker(CommandInvoker): # pylint: disable=too-many-statements,too-many-locals def execute(self, args): - import knack.events as events + from knack.events import (EVENT_INVOKER_PRE_CMD_TBL_CREATE, EVENT_INVOKER_POST_CMD_TBL_CREATE, + EVENT_INVOKER_CMD_TBL_LOADED, EVENT_INVOKER_PRE_PARSE_ARGS, + EVENT_INVOKER_POST_PARSE_ARGS, EVENT_INVOKER_TRANSFORM_RESULT, + EVENT_INVOKER_FILTER_RESULT) from knack.util import CommandResultItem, todict from azure.cli.core.commands.events import EVENT_INVOKER_PRE_CMD_TBL_TRUNCATE # TODO: Can't simply be invoked as an event because args are transformed args = _pre_command_table_create(self.cli_ctx, args) - self.cli_ctx.raise_event(events.EVENT_INVOKER_PRE_CMD_TBL_CREATE, args=args) + self.cli_ctx.raise_event(EVENT_INVOKER_PRE_CMD_TBL_CREATE, args=args) self.commands_loader.load_command_table(args) self.cli_ctx.raise_event(EVENT_INVOKER_PRE_CMD_TBL_TRUNCATE, load_cmd_tbl_func=self.commands_loader.load_command_table, args=args) command = self._rudimentary_get_command(args) + telemetry.set_raw_command_name(command) try: self.commands_loader.command_table = {command: self.commands_loader.command_table[command]} @@ -250,11 +253,11 @@ def execute(self, args): self.commands_loader.command_table = self.commands_loader.command_table # update with the truncated table self.commands_loader.command_name = command self.commands_loader.load_arguments(command) - self.cli_ctx.raise_event(events.EVENT_INVOKER_POST_CMD_TBL_CREATE, cmd_tbl=self.commands_loader.command_table) + self.cli_ctx.raise_event(EVENT_INVOKER_POST_CMD_TBL_CREATE, cmd_tbl=self.commands_loader.command_table) self.parser.cli_ctx = self.cli_ctx self.parser.load_command_table(self.commands_loader.command_table) - self.cli_ctx.raise_event(events.EVENT_INVOKER_CMD_TBL_LOADED, cmd_tbl=self.commands_loader.command_table, + self.cli_ctx.raise_event(EVENT_INVOKER_CMD_TBL_LOADED, cmd_tbl=self.commands_loader.command_table, parser=self.parser) if not args: @@ -272,9 +275,9 @@ def execute(self, args): self.cli_ctx.completion.enable_autocomplete(self.parser) - self.cli_ctx.raise_event(events.EVENT_INVOKER_PRE_PARSE_ARGS, args=args) + self.cli_ctx.raise_event(EVENT_INVOKER_PRE_PARSE_ARGS, args=args) parsed_args = self.parser.parse_args(args) - self.cli_ctx.raise_event(events.EVENT_INVOKER_POST_PARSE_ARGS, command=parsed_args.command, args=parsed_args) + self.cli_ctx.raise_event(EVENT_INVOKER_POST_PARSE_ARGS, command=parsed_args.command, args=parsed_args) # TODO: This fundamentally alters the way Knack.invocation works here. Cannot be customized # with an event. Would need to be customized via inheritance. @@ -326,8 +329,8 @@ def execute(self, args): result = todict(result) event_data = {'result': result} - self.cli_ctx.raise_event(events.EVENT_INVOKER_TRANSFORM_RESULT, event_data=event_data) - self.cli_ctx.raise_event(events.EVENT_INVOKER_FILTER_RESULT, event_data=event_data) + self.cli_ctx.raise_event(EVENT_INVOKER_TRANSFORM_RESULT, event_data=event_data) + self.cli_ctx.raise_event(EVENT_INVOKER_FILTER_RESULT, event_data=event_data) result = event_data['result'] results.append(result) diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py index 44f766e5e58..6348f014948 100644 --- a/src/azure-cli-core/azure/cli/core/telemetry.py +++ b/src/azure-cli-core/azure/cli/core/telemetry.py @@ -42,8 +42,10 @@ class TelemetrySession(object): # pylint: disable=too-many-instance-attributes extension_version = None feedback = None extension_management_detail = None + raw_command = None def add_exception(self, exception, fault_type, description=None, message=''): + fault_type = _remove_symbols(fault_type).replace('"', '').replace("'", '').replace(' ', '-') details = { 'Reserved.DataModel.EntityType': 'Fault', 'Reserved.DataModel.Fault.Description': description or fault_type, @@ -51,10 +53,11 @@ def add_exception(self, exception, fault_type, description=None, message=''): 'Reserved.DataModel.Fault.TypeString': exception.__class__.__name__, 'Reserved.DataModel.Fault.Exception.Message': _remove_cmd_chars( message or str(exception)), - 'Reserved.DataModel.Fault.Exception.StackTrace': _remove_cmd_chars(_get_stack_trace()) + 'Reserved.DataModel.Fault.Exception.StackTrace': _remove_cmd_chars(_get_stack_trace()), + AZURE_CLI_PREFIX + 'FaultType': fault_type.lower() } - fault_type = _remove_symbols(fault_type).replace('"', '').replace("'", '').replace(' ', '-') - fault_name = '{}/commands/{}'.format(PRODUCT_NAME, fault_type.lower()) + + fault_name = '{}/fault'.format(PRODUCT_NAME) self.exceptions.append((fault_name, details)) @@ -68,7 +71,7 @@ def generate_payload(self): user_task.update(base) user_task.update(cli) - events.append({'name': self.event_name, 'properties': user_task}) + events.append({'name': '{}/command'.format(PRODUCT_NAME), 'properties': user_task}) for name, props in self.exceptions: props.update(base) @@ -144,6 +147,7 @@ def _get_azure_cli_properties(self): self.set_custom_properties(result, 'StartTime', str(self.start_time)) self.set_custom_properties(result, 'EndTime', str(self.end_time)) self.set_custom_properties(result, 'OutputType', self.output_type) + self.set_custom_properties(result, 'RawCommand', self.raw_command) self.set_custom_properties(result, 'Params', ','.join(self.parameters or [])) self.set_custom_properties(result, 'PythonVersion', platform.python_version()) self.set_custom_properties(result, 'ModuleCorrelation', self.module_correlation) @@ -157,17 +161,13 @@ def _get_azure_cli_properties(self): def command_name(self): return self.command.lower().replace('-', '').replace(' ', '-') - @property - def event_name(self): - return '{}/{}/{}'.format(PRODUCT_NAME, self.feature_name, self.command_name) - @property def feature_name(self): # The feature name is used to created the event name. The feature name should be eventually # the module name. However, it takes time to resolve the actual module name using pip # module. Therefore, a hard coded replacement is used before a better solution is # implemented - return 'commands' + return 'command' @property def module_version(self): @@ -288,6 +288,12 @@ def set_module_correlation_data(correlation_data): _session.module_correlation = correlation_data[:512] +@decorators.suppress_all_exceptions(raise_in_diagnostics=True) +def set_raw_command_name(command): + # the raw command name user inputs + _session.raw_command = command + + # definitions @decorators.call_once