azure-devops/azext_devops/dev/common/telemetry.py (86 lines of code) (raw):
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import threading
from knack.log import get_logger
from azext_devops.devops_sdk.v5_0.customer_intelligence.models import CustomerIntelligenceEvent
logger = get_logger(__name__)
vsts_tracking_data = CustomerIntelligenceEvent()
def init_telemetry():
global vsts_tracking_data # pylint: disable=global-statement
if vsts_tracking_data is None:
vsts_tracking_data = CustomerIntelligenceEvent()
if vsts_tracking_data.properties is None:
vsts_tracking_data.properties = {}
def try_send_telemetry_data(organization):
try:
if _is_telemetry_enabled():
logger.debug('Azure devops telemetry enabled.')
_try_send_tracking_ci_event_async(organization)
else:
logger.debug('Azure devops telemetry disabled.')
except BaseException as ex: # pylint: disable=broad-except
logger.debug(ex, exc_info=True)
logger.debug('Azure devops telemetry sending failed.')
def set_tracking_data(**kwargs):
init_telemetry()
try:
vsts_tracking_data.area = 'AzureDevopsCli'
vsts_tracking_data.properties = {}
command_line_args = vars(kwargs.get('args', None))
command_line_split = command_line_args['command'].split()
vsts_tracking_data.feature = command_line_split[0]
if len(command_line_split) > 1:
vsts_tracking_data.properties['Command'] = ' '.join(command_line_split[1:])
args = []
for key, value in command_line_args.items():
if value and isinstance(value, str) and not key.startswith('_') and key != 'command':
args.append(key)
vsts_tracking_data.properties['Args'] = ' '.join(args)
vsts_tracking_data.properties['ShellType'] = _get_shell_type()
import sys
vsts_tracking_data.properties['IsInteractive'] = str(sys.stdin.isatty())
vsts_tracking_data.properties['OutputType'] = command_line_args['_output_format']
except BaseException as ex: # pylint: disable=broad-except
logger.debug(ex, exc_info=True)
def _is_telemetry_enabled():
from azure.cli.core.telemetry import is_telemetry_enabled
return is_telemetry_enabled()
def _try_send_tracking_ci_event_async(organization=None):
if (vsts_tracking_data is not None and vsts_tracking_data.area is not None and
vsts_tracking_data.feature is not None):
logger.debug("Logging telemetry to azure devops server.")
try:
thread = threading.Thread(target=_send_tracking_ci_event, args=[organization])
thread.start()
except BaseException as ex: # pylint: disable=broad-except
# we should always continue if we fail to set tracking data
logger.debug(ex, exc_info=True)
else:
logger.debug("Skipping telemetry to azure devops server.")
def _send_tracking_ci_event(organization=None, ci_client=None):
from .services import get_ci_client
if ci_client is None:
ci_client = get_ci_client(organization=organization)
try:
ci_client.publish_events([vsts_tracking_data])
return True
except BaseException as ex: # pylint: disable=broad-except
logger.debug(ex, exc_info=True)
return False
# azure cli uses this to get shell type from os environment
def _get_shell_type():
import os
if 'ZSH_VERSION' in os.environ:
return 'zsh'
if 'BASH_VERSION' in os.environ:
return 'bash'
if 'KSH_VERSION' in os.environ or 'FCEDIT' in os.environ:
return 'ksh'
if 'WINDIR' in os.environ:
return 'cmd'
return _remove_cmd_chars(_remove_symbols(os.environ.get('SHELL')))
def _remove_cmd_chars(s):
if isinstance(s, str):
return s.replace("'", '_').replace('"', '_').replace('\r\n', ' ').replace('\n', ' ')
return s
def _remove_symbols(s):
if isinstance(s, str):
for c in '$%^&|':
s = s.replace(c, '_')
return s