Skip to content

Commit

Permalink
Update telemetry data format (Azure#5605)
Browse files Browse the repository at this point in the history
1. Simplify event names. Instead of putting command name in the event
name, the event names will be reduced to azurecli/command and
azurecli/fault.
2. Collect the raw command name which was failed to be collect since the
set_application_details happens after the argument parsing. When there
is incorrect argument names, the command name will be missing.
  • Loading branch information
troydai authored Feb 20, 2018
1 parent a0661eb commit 921b825
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 18 deletions.
21 changes: 12 additions & 9 deletions src/azure-cli-core/azure/cli/core/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]}
Expand Down Expand Up @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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)

Expand Down
24 changes: 15 additions & 9 deletions src/azure-cli-core/azure/cli/core/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,22 @@ 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,
'Reserved.DataModel.Correlation.1': '{},UserTask,'.format(self.correlation_id),
'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))

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 921b825

Please sign in to comment.