Repository: Azure/WALinuxAgent
Pull request #2938 (2023-10-05 17:59:37)

Add Cpu Arch in local logs and telemetry events
<!-- DO NOT DELETE THIS TEMPLATE -->

## Description
This PR adds CPU Arch to local logs during service initialization. It also adds CPU Arch to the 'KeywordName' column as a common parameter in our telemetry events.

Local logs:
2023-10-05T02:07:24.787099Z INFO ExtHandler ExtHandler Azure Linux Agent (Goal State Agent version 9.9.9.9)
2023-10-05T02:07:24.787282Z INFO ExtHandler ExtHandler OS: ubuntu 20.04
2023-10-05T02:07:24.787379Z INFO ExtHandler ExtHandler Python: 3.8.10
2023-10-05T02:07:24.787477Z INFO ExtHandler ExtHandler **CPU Arch: x86_64**
2023-10-05T02:07:24.795884Z INFO ExtHandler ExtHandler Distro: ubuntu-20.04; OSUtil: Ubuntu18OSUtil; AgentService: walinuxagent; Python: 3.8.10; **Arch: x86_64**; systemd: True; LISDrivers: name:           hv_vmbus
; logrotate: logrotate 3.14.0;

Telemetry:
OpcodeName | Name | KeywordName | Operation | OperationSuccess | Message
-- | -- | -- | -- | -- | --
2023-10-05T02:07:25.167405Z | WALinuxAgent | {"CpuArchitecture": "x86_64"} | OSInfo | true | Distro: ubuntu-20.04; OSUtil: Ubuntu18OSUtil; AgentService: walinuxagent; Python: 3.8.10; Arch: x86_64; systemd: True; LISDrivers: name:           hv_vmbus ; logrotate: logrotate 3.14.0;

</div>

Issue # <!-- if any -->
<!--
Please add an informative description that covers that changes made by the pull request. 
This checklist is used to make sure that common issues in a pull request are addressed.
This will expedite the process of getting your pull request merged and avoid extra work on your part to fix issues discovered during the review process.
-->

---

### PR information
- [ ] The title of the PR is clear and informative.
- [ ] There are a small number of commits, each of which has an informative message. This means that previously merged commits do not appear in the history of the PR. For information on cleaning up the commits in your pull request, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md).
- [ ] If applicable, the PR references the bug/issue that it fixes in the description.
- [ ] New Unit tests were added for the changes made

### Quality of Code and Contribution Guidelines
- [ ] I have read the [contribution guidelines](https://github.com/Azure/WALinuxAgent/blob/master/.github/CONTRIBUTING.md).

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Azure/WALinuxAgent/pull/2938?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azure) Report
> Merging [#2938](https://app.codecov.io/gh/Azure/WALinuxAgent/pull/2938?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azure) (f712f3e) into [develop](https://app.codecov.io/gh/Azure/WALinuxAgent/commit/8bfad4d7b1cbfb35a4ea8d1170248060bb4fdacd?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azure) (8bfad4d) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

```diff
@@             Coverage Diff             @@
##           develop    #2938      +/-   ##
===========================================
+ Coverage    71.98%   71.99%   +0.01%     
===========================================
  Files          106      106              
  Lines        16079    16085       +6     
  Branches      2303     2303              
===========================================
+ Hits         11574    11580       +6     
  Misses        3972     3972              
  Partials       533      533              
```


| [Files](https://app.codecov.io/gh/Azure/WALinuxAgent/pull/2938?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azure) | Coverage Δ | |
|---|---|---|
| [azurelinuxagent/common/event.py](https://app.codecov.io/gh/Azure/WALinuxAgent/pull/2938?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azure#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9ldmVudC5weQ==) | `85.58% <100.00%> (+0.12%)` | :arrow_up: |
| [azurelinuxagent/ga/update.py](https://app.codecov.io/gh/Azure/WALinuxAgent/pull/2938?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azure#diff-YXp1cmVsaW51eGFnZW50L2dhL3VwZGF0ZS5weQ==) | `87.57% <100.00%> (+0.03%)` | :arrow_up: |



Patch:
diff --git a/azurelinuxagent/common/event.py b/azurelinuxagent/common/event.py
index 95abf09e..514c727f 100644
--- a/azurelinuxagent/common/event.py
+++ b/azurelinuxagent/common/event.py
@@ -366,10 +366,14 @@ class EventLogger(object):
 
         # Parameters from OS
         osutil = get_osutil()
+        keyword_name = {
+            "CpuArchitecture": osutil.get_vm_arch()
+        }
         self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.OSVersion, EventLogger._get_os_version()))
         self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.ExecutionMode, AGENT_EXECUTION_MODE))
         self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.RAM, int(EventLogger._get_ram(osutil))))
         self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.Processors, int(EventLogger._get_processors(osutil))))
+        self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.KeywordName, json.dumps(keyword_name)))
 
         # Parameters from goal state
         self._common_parameters.append(TelemetryEventParam(CommonTelemetryEventSchema.TenantName, "TenantName_UNINITIALIZED"))
@@ -597,8 +601,7 @@ class EventLogger(object):
                          TelemetryEventParam(CommonTelemetryEventSchema.OpcodeName, event_timestamp.strftime(logger.Logger.LogTimeFormatInUTC)),
                          TelemetryEventParam(CommonTelemetryEventSchema.EventTid, threading.current_thread().ident),
                          TelemetryEventParam(CommonTelemetryEventSchema.EventPid, os.getpid()),
-                         TelemetryEventParam(CommonTelemetryEventSchema.TaskName, threading.current_thread().getName()),
-                         TelemetryEventParam(CommonTelemetryEventSchema.KeywordName, '')]
+                         TelemetryEventParam(CommonTelemetryEventSchema.TaskName, threading.current_thread().getName())]
 
         if event.eventId == TELEMETRY_EVENT_EVENT_ID and event.providerId == TELEMETRY_EVENT_PROVIDER_ID:
             # Currently only the GuestAgentExtensionEvents has these columns, the other tables dont have them so skipping
diff --git a/azurelinuxagent/common/osutil/default.py b/azurelinuxagent/common/osutil/default.py
index 6430f83e..69e20bea 100644
--- a/azurelinuxagent/common/osutil/default.py
+++ b/azurelinuxagent/common/osutil/default.py
@@ -149,6 +149,14 @@ class DefaultOSUtil(object):
     def get_agent_bin_path():
         return "/usr/sbin"
 
+    @staticmethod
+    def get_vm_arch():
+        try:
+            return platform.machine()
+        except Exception as e:
+            logger.warn("Unable to determine cpu architecture: {0}", ustr(e))
+            return "unknown"
+
     def get_firewall_dropped_packets(self, dst_ip=None):
         # If a previous attempt failed, do not retry
         global _enable_firewall  # pylint: disable=W0603
diff --git a/azurelinuxagent/ga/update.py b/azurelinuxagent/ga/update.py
index cd37a32e..14740270 100644
--- a/azurelinuxagent/ga/update.py
+++ b/azurelinuxagent/ga/update.py
@@ -315,10 +315,14 @@ class UpdateHandler(object):
             logger.info("OS: {0} {1}", DISTRO_NAME, DISTRO_VERSION)
             logger.info("Python: {0}.{1}.{2}", PY_VERSION_MAJOR, PY_VERSION_MINOR, PY_VERSION_MICRO)
 
+            vm_arch = self.osutil.get_vm_arch()
+            logger.info("CPU Arch: {0}", vm_arch)
+
             os_info_msg = u"Distro: {dist_name}-{dist_ver}; "\
                 u"OSUtil: {util_name}; "\
                 u"AgentService: {service_name}; "\
                 u"Python: {py_major}.{py_minor}.{py_micro}; "\
+                u"Arch: {vm_arch}; "\
                 u"systemd: {systemd}; "\
                 u"LISDrivers: {lis_ver}; "\
                 u"logrotate: {has_logrotate};".format(
@@ -326,7 +330,7 @@ class UpdateHandler(object):
                     util_name=type(self.osutil).__name__,
                     service_name=self.osutil.service_name,
                     py_major=PY_VERSION_MAJOR, py_minor=PY_VERSION_MINOR,
-                    py_micro=PY_VERSION_MICRO, systemd=systemd.is_systemd(),
+                    py_micro=PY_VERSION_MICRO, vm_arch=vm_arch, systemd=systemd.is_systemd(),
                     lis_ver=get_lis_version(), has_logrotate=has_logrotate()
                 )
             logger.info(os_info_msg)
@@ -1013,13 +1017,10 @@ class UpdateHandler(object):
         if datetime.utcnow() >= (self._last_telemetry_heartbeat + UpdateHandler.TELEMETRY_HEARTBEAT_PERIOD):
             dropped_packets = self.osutil.get_firewall_dropped_packets(protocol.get_endpoint())
             auto_update_enabled = 1 if conf.get_autoupdate_enabled() else 0
-            # Include vm architecture in the heartbeat message because the kusto table does not have
-            # a separate column for it.
-            vmarch = self._get_vm_arch()
 
-            telemetry_msg = "{0};{1};{2};{3};{4};{5}".format(self._heartbeat_counter, self._heartbeat_id, dropped_packets,
+            telemetry_msg = "{0};{1};{2};{3};{4}".format(self._heartbeat_counter, self._heartbeat_id, dropped_packets,
                                                          self._heartbeat_update_goal_state_error_count,
-                                                         auto_update_enabled, vmarch)
+                                                         auto_update_enabled)
             debug_log_msg = "[DEBUG HeartbeatCounter: {0};HeartbeatId: {1};DroppedPackets: {2};" \
                             "UpdateGSErrors: {3};AutoUpdate: {4}]".format(self._heartbeat_counter,
                                                                           self._heartbeat_id, dropped_packets,


Test patch:
diff --git a/tests/common/test_event.py b/tests/common/test_event.py
index 28f2e386..435ac2e8 100644
--- a/tests/common/test_event.py
+++ b/tests/common/test_event.py
@@ -20,6 +20,7 @@ from __future__ import print_function
 
 import json
 import os
+import platform
 import re
 import shutil
 import threading
@@ -70,7 +71,7 @@ class TestEvent(HttpRequestPredicates, AgentTestCase):
             CommonTelemetryEventSchema.EventTid: threading.current_thread().ident,
             CommonTelemetryEventSchema.EventPid: os.getpid(),
             CommonTelemetryEventSchema.TaskName: threading.current_thread().getName(),
-            CommonTelemetryEventSchema.KeywordName: '',
+            CommonTelemetryEventSchema.KeywordName: json.dumps({"CpuArchitecture": platform.machine()}),
             # common parameters computed from the OS platform
             CommonTelemetryEventSchema.OSVersion: EventLoggerTools.get_expected_os_version(),
             CommonTelemetryEventSchema.ExecutionMode: AGENT_EXECUTION_MODE,
diff --git a/tests/ga/test_send_telemetry_events.py b/tests/ga/test_send_telemetry_events.py
index c9e04a38..a9c87dde 100644
--- a/tests/ga/test_send_telemetry_events.py
+++ b/tests/ga/test_send_telemetry_events.py
@@ -368,13 +368,13 @@ class TestSendTelemetryEventsHandler(AgentTestCase, HttpRequestPredicates):
                              '<Param Name="EventTid" Value="{4}" T="mt:uint64" />' \
                              '<Param Name="EventPid" Value="{5}" T="mt:uint64" />' \
                              '<Param Name="TaskName" Value="{6}" T="mt:wstr" />' \
-                             '<Param Name="KeywordName" Value="" T="mt:wstr" />' \
                              '<Param Name="ExtensionType" Value="json" T="mt:wstr" />' \
                              '<Param Name="IsInternal" Value="False" T="mt:bool" />' \
                              '<Param Name="OSVersion" Value="{7}" T="mt:wstr" />' \
                              '<Param Name="ExecutionMode" Value="IAAS" T="mt:wstr" />' \
                              '<Param Name="RAM" Value="{8}" T="mt:uint64" />' \
                              '<Param Name="Processors" Value="{9}" T="mt:uint64" />' \
+                             '<Param Name="KeywordName" Value=\'{10}\' T="mt:wstr" />' \
                              '<Param Name="TenantName" Value="db00a7755a5e4e8a8fe4b19bc3b330c3" T="mt:wstr" />' \
                              '<Param Name="RoleName" Value="MachineRole" T="mt:wstr" />' \
                              '<Param Name="RoleInstanceName" Value="b61f93d0-e1ed-40b2-b067-22c243233448.MachineRole_IN_0" T="mt:wstr" />' \
@@ -385,7 +385,7 @@ class TestSendTelemetryEventsHandler(AgentTestCase, HttpRequestPredicates):
                              '<Param Name="ImageOrigin" Value="2468" T="mt:uint64" />' \
                              ']]></Event>'.format(AGENT_VERSION, TestSendTelemetryEventsHandler._TEST_EVENT_OPERATION, CURRENT_AGENT, test_opcodename, test_eventtid,
                                                   test_eventpid, test_taskname, osversion, int(osutil.get_total_mem()),
-                                                  osutil.get_processor_cores()).encode('utf-8')
+                                                  osutil.get_processor_cores(), json.dumps({"CpuArchitecture": platform.machine()})).encode('utf-8')
 
             self.assertIn(sample_message, collected_event)