diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py index cc10885e88b..852c6468b30 100644 --- a/src/azure-cli-core/azure/cli/core/telemetry.py +++ b/src/azure-cli-core/azure/cli/core/telemetry.py @@ -104,7 +104,7 @@ def _get_base_properties(self): 'Reserved.ChannelUsed': 'AI', 'Reserved.EventId': str(uuid.uuid4()), 'Reserved.SequenceNumber': 1, - 'Reserved.SessionId': str(uuid.uuid4()), + 'Reserved.SessionId': _get_session_id(), 'Reserved.TimeSinceSessionStart': 0, 'Reserved.DataModel.Source': 'DataModelAPI', @@ -407,6 +407,33 @@ def _get_installation_id(): return _get_profile().get_installation_id() +@decorators.suppress_all_exceptions(fallback_return="") +def _get_session_id(): + # As a workaround to get the terminal info as SessionId, this function may not be accurate. + + def get_hash_result(content): + import hashlib + + hasher = hashlib.sha256() + hasher.update(content.encode('utf-8')) + return hasher.hexdigest() + + # Usually, more than one layer of sub-process will be started when excuting a CLI command. While, the create time + # of these sub-processes will be very close, usually in several milliseconds. We use 1 second as the threshold here. + # When the difference of create time between current process and its parent process is larger than the threshold, + # the parent process will be viewed as the terminal process. + import psutil + time_threshold = 1 + process = psutil.Process() + while process and process.ppid() and process.pid != process.ppid(): + parent_process = process.parent() + if parent_process and process.create_time() - parent_process.create_time() > time_threshold: + content = '{}{}{}'.format(_get_installation_id(), parent_process.create_time(), parent_process.pid) + return get_hash_result(content) + process = parent_process + return "" + + @decorators.call_once @decorators.suppress_all_exceptions(fallback_return=None) def _get_profile(): diff --git a/src/azure-cli/requirements.py3.Darwin.txt b/src/azure-cli/requirements.py3.Darwin.txt index 90ff777b923..02d9b951e14 100644 --- a/src/azure-cli/requirements.py3.Darwin.txt +++ b/src/azure-cli/requirements.py3.Darwin.txt @@ -108,6 +108,7 @@ oauthlib==3.0.1 paramiko==2.6.0 pbr==5.3.1 portalocker==1.4.0 +psutil==5.7.2 pycparser==2.19 PyJWT==1.7.1 PyNaCl==1.3.0 diff --git a/src/azure-cli/requirements.py3.Linux.txt b/src/azure-cli/requirements.py3.Linux.txt index 90ff777b923..02d9b951e14 100644 --- a/src/azure-cli/requirements.py3.Linux.txt +++ b/src/azure-cli/requirements.py3.Linux.txt @@ -108,6 +108,7 @@ oauthlib==3.0.1 paramiko==2.6.0 pbr==5.3.1 portalocker==1.4.0 +psutil==5.7.2 pycparser==2.19 PyJWT==1.7.1 PyNaCl==1.3.0 diff --git a/src/azure-cli/requirements.py3.windows.txt b/src/azure-cli/requirements.py3.windows.txt index 8bd62e5f3c7..6294a4eb3f7 100644 --- a/src/azure-cli/requirements.py3.windows.txt +++ b/src/azure-cli/requirements.py3.windows.txt @@ -106,6 +106,7 @@ oauthlib==3.0.1 paramiko==2.6.0 pbr==5.3.1 portalocker==1.2.1 +psutil==5.7.2 pycparser==2.19 PyJWT==1.7.1 PyNaCl==1.3.0 diff --git a/src/azure-cli/setup.py b/src/azure-cli/setup.py index 7636fc411e0..ea60cbc82ff 100644 --- a/src/azure-cli/setup.py +++ b/src/azure-cli/setup.py @@ -139,6 +139,10 @@ 'jsondiff==1.2.0' ] +# dependencies for specific OSes +if not sys.platform.startswith('cygwin'): + DEPENDENCIES.append('psutil~=5.7') + TESTS_REQUIRE = [ 'mock~=4.0' ]