Skip to content

Commit 6cad351

Browse files
derekbekoetroydai
authored andcommitted
Extension telemetry (include versions) (#5512)
* Send extension version for extension command usage also. * Send extension version as well for 'az extension add/remove/update'
1 parent 074a237 commit 6cad351

4 files changed

Lines changed: 51 additions & 14 deletions

File tree

src/azure-cli-core/azure/cli/core/commands/__init__.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from knack.util import CLIError
2121

2222
from azure.cli.core import EXCLUDED_PARAMS
23+
from azure.cli.core.extension import get_extension
2324
import azure.cli.core.telemetry as telemetry
2425

2526
logger = get_logger(__name__)
@@ -189,7 +190,7 @@ def get_models(self, *attr_args, **kwargs):
189190
# pylint: disable=too-few-public-methods
190191
class AzCliCommandInvoker(CommandInvoker):
191192

192-
# pylint: disable=too-many-statements
193+
# pylint: disable=too-many-statements,too-many-locals
193194
def execute(self, args):
194195
import knack.events as events
195196
from knack.util import CommandResultItem, todict
@@ -283,10 +284,19 @@ def execute(self, args):
283284
params = self._filter_params(expanded_arg)
284285

285286
command_source = self.commands_loader.command_table[command].command_source
287+
288+
extension_version = None
289+
try:
290+
if command_source:
291+
extension_version = get_extension(command_source.extension_name).version
292+
except Exception: # pylint: disable=broad-except
293+
pass
294+
286295
telemetry.set_command_details(self.cli_ctx.data['command'], self.data['output'],
287296
[(p.split('=', 1)[0] if p.startswith('--') else p[:2]) for p in args if
288297
(p.startswith('-') and len(p) > 1)],
289-
extension_name=command_source.extension_name if command_source else None)
298+
extension_name=command_source.extension_name if command_source else None,
299+
extension_version=extension_version)
290300
if command_source:
291301
self.data['command_extension_name'] = command_source.extension_name
292302

src/azure-cli-core/azure/cli/core/parser.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from knack.util import CLIError
1414

1515
import azure.cli.core.telemetry as telemetry
16-
16+
from azure.cli.core.extension import get_extension
1717

1818
logger = get_logger(__name__)
1919

@@ -109,9 +109,17 @@ def error(self, message):
109109
self.exit(2)
110110

111111
def format_help(self):
112+
extension_version = None
113+
try:
114+
if self.command_source:
115+
extension_version = get_extension(self.command_source.extension_name).version
116+
except Exception: # pylint: disable=broad-except
117+
pass
118+
112119
telemetry.set_command_details(
113120
command=self.prog[3:],
114-
extension_name=self.command_source.extension_name if self.command_source else None)
121+
extension_name=self.command_source.extension_name if self.command_source else None,
122+
extension_version=extension_version)
115123
telemetry.set_success(summary='show help')
116124
super(AzCliCommandParser, self).format_help()
117125

src/azure-cli-core/azure/cli/core/telemetry.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class TelemetrySession(object): # pylint: disable=too-many-instance-attributes
3838
payload_properties = None
3939
exceptions = []
4040
module_correlation = None
41-
extension_name = 'None'
41+
extension_name = None
42+
extension_version = None
4243
feedback = None
4344
extension_management_detail = None
4445

@@ -124,6 +125,7 @@ def _get_user_task_properties(self):
124125
def _get_azure_cli_properties(self):
125126
source = 'az' if self.arg_complete_env_name not in os.environ else 'completer'
126127
result = {}
128+
ext_info = '{}@{}'.format(self.extension_name, self.extension_version) if self.extension_name else None
127129
self.set_custom_properties(result, 'Source', source)
128130
self.set_custom_properties(result,
129131
'ClientRequestId',
@@ -145,9 +147,9 @@ def _get_azure_cli_properties(self):
145147
self.set_custom_properties(result, 'Params', ','.join(self.parameters or []))
146148
self.set_custom_properties(result, 'PythonVersion', platform.python_version())
147149
self.set_custom_properties(result, 'ModuleCorrelation', self.module_correlation)
148-
self.set_custom_properties(result, 'ExtensionName', self.extension_name)
150+
self.set_custom_properties(result, 'ExtensionName', ext_info)
149151
self.set_custom_properties(result, 'Feedback', self.feedback)
150-
self.set_custom_properties(result, 'ExtensionManagement', self.extension_management_detail)
152+
self.set_custom_properties(result, 'ExtensionManagementDetail', self.extension_management_detail)
151153

152154
return result
153155

@@ -267,16 +269,18 @@ def set_feedback(feedback):
267269

268270

269271
@decorators.suppress_all_exceptions(raise_in_diagnostics=True)
270-
def set_extension_management_detail(content):
272+
def set_extension_management_detail(ext_name, ext_version):
273+
content = '{}@{}'.format(ext_name, ext_version)
271274
_session.extension_management_detail = content[:512]
272275

273276

274277
@decorators.suppress_all_exceptions(raise_in_diagnostics=True)
275-
def set_command_details(command, output_type=None, parameters=None, extension_name=None):
278+
def set_command_details(command, output_type=None, parameters=None, extension_name=None, extension_version=None):
276279
_session.command = command
277280
_session.output_type = output_type
278281
_session.parameters = parameters
279-
_session.extension_name = extension_name or 'None'
282+
_session.extension_name = extension_name
283+
_session.extension_version = extension_version
280284

281285

282286
@decorators.suppress_all_exceptions(raise_in_diagnostics=True)

src/command_modules/azure-cli-extension/azure/cli/command_modules/extension/custom.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,19 @@ def is_valid_sha256sum(a_file, expected_sum):
168168
return expected_sum == computed_hash, computed_hash
169169

170170

171+
def _augment_telemetry_with_ext_info(extension_name):
172+
# The extension must be available before calling this otherwise we can't get the version from metadata
173+
if not extension_name:
174+
return
175+
try:
176+
ext = get_extension(extension_name)
177+
ext_version = ext.version
178+
set_extension_management_detail(extension_name, ext_version)
179+
except Exception: # nopa pylint: disable=broad-except
180+
# Don't error on telemetry
181+
pass
182+
183+
171184
def add_extension(source=None, extension_name=None, index_url=None, yes=None, # pylint: disable=unused-argument
172185
pip_extra_index_urls=None, pip_proxy=None):
173186
ext_sha256 = None
@@ -180,16 +193,16 @@ def add_extension(source=None, extension_name=None, index_url=None, yes=None, #
180193
logger.debug(err)
181194
raise CLIError("No matching extensions for '{}'. Use --debug for more information.".format(extension_name))
182195
_add_whl_ext(source, ext_sha256=ext_sha256, pip_extra_index_urls=pip_extra_index_urls, pip_proxy=pip_proxy)
183-
184-
if extension_name:
185-
set_extension_management_detail(extension_name)
196+
_augment_telemetry_with_ext_info(extension_name)
186197

187198

188199
def remove_extension(extension_name):
189200
try:
201+
# Get the extension and it will raise an error if it doesn't exist
190202
get_extension(extension_name)
203+
# We call this just before we remove the extension so we can get the metadata before it is gone
204+
_augment_telemetry_with_ext_info(extension_name)
191205
shutil.rmtree(get_extension_path(extension_name))
192-
set_extension_management_detail(extension_name)
193206
except ExtensionNotInstalledException as e:
194207
raise CLIError(e)
195208

@@ -232,6 +245,8 @@ def update_extension(extension_name, index_url=None, pip_extra_index_urls=None,
232245
pip_extra_index_urls=pip_extra_index_urls, pip_proxy=pip_proxy)
233246
logger.debug('Deleting backup of old extension at %s', backup_dir)
234247
shutil.rmtree(backup_dir)
248+
# This gets the metadata for the extension *after* the update
249+
_augment_telemetry_with_ext_info(extension_name)
235250
except Exception as err:
236251
logger.error('An error occurred whilst updating.')
237252
logger.error(err)

0 commit comments

Comments
 (0)