[ESP32] Added the support to report the chip system statistics to the esp-insights. (#29158)

* Added the support to report the chip system statistics to the esp-insights.

- The system stats from src/system/SystemStats.h are reported on enabling a config option to esp-insights.

* Addressed review comments
diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt
index e32588d..e812480 100644
--- a/config/esp32/components/chip/CMakeLists.txt
+++ b/config/esp32/components/chip/CMakeLists.txt
@@ -262,6 +262,10 @@
   chip_gn_arg_append("matter_trace_config" "\"${CHIP_ROOT}/src/tracing/esp32_trace:esp32_trace_tracing\"")
 endif()
 
+if (CONFIG_ENABLE_ESP_INSIGHTS_SYSTEM_STATS)
+     chip_gn_arg_append("matter_enable_esp_insights_system_stats"            "true")
+endif()
+
 if (CONFIG_USE_ESP32_ECDSA_PERIPHERAL)
     chip_gn_arg_append("chip_use_esp32_ecdsa_peripheral" "true")
 endif()
diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig
index b73398b..ec2ab1a 100644
--- a/config/esp32/components/chip/Kconfig
+++ b/config/esp32/components/chip/Kconfig
@@ -876,6 +876,12 @@
                Enabling the above option will enable the esp32 specific tracing functionality and report the
                diagnostic information to the insights cloud.
 
+      config ENABLE_ESP_INSIGHTS_SYSTEM_STATS
+           bool "Enable System Stats for insights"
+           depends on ESP_INSIGHTS_ENABLED
+           default n
+           help
+               This option enables the system statistics to be sent to the insights cloud.
     endmenu
 
 
diff --git a/examples/lighting-app/esp32/main/main.cpp b/examples/lighting-app/esp32/main/main.cpp
index 5b79e3d..5957a68 100644
--- a/examples/lighting-app/esp32/main/main.cpp
+++ b/examples/lighting-app/esp32/main/main.cpp
@@ -39,6 +39,11 @@
 #include <credentials/examples/DeviceAttestationCredsExample.h>
 #include <platform/ESP32/ESP32Utils.h>
 
+#if CONFIG_ENABLE_ESP_INSIGHTS_SYSTEM_STATS
+#include <tracing/esp32_trace/insights_sys_stats.h>
+#define START_TIMEOUT_MS 600000
+#endif
+
 #if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER
 #include <platform/ESP32/ESP32FactoryDataProvider.h>
 #endif // CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER
@@ -115,6 +120,7 @@
 
     DeviceCallbacksDelegate::Instance().SetAppDelegate(&sAppDeviceCallbacksDelegate);
     Esp32AppServer::Init(); // Init ZCL Data Model and CHIP App Server AND Initialize device attestation config
+
 #if CONFIG_ENABLE_ESP_INSIGHTS_TRACE
     esp_insights_config_t config = {
         .log_type = ESP_DIAG_LOG_TYPE_ERROR | ESP_DIAG_LOG_TYPE_WARNING | ESP_DIAG_LOG_TYPE_EVENT,
@@ -130,6 +136,10 @@
 
     static Tracing::Insights::ESP32Backend backend;
     Tracing::Register(backend);
+
+#if CONFIG_ENABLE_ESP_INSIGHTS_SYSTEM_STATS
+    chip::System::Stats::InsightsSystemMetrics::GetInstance().RegisterAndEnable(chip::System::Clock::Timeout(START_TIMEOUT_MS));
+#endif
 #endif
 }
 
diff --git a/src/tracing/esp32_trace/BUILD.gn b/src/tracing/esp32_trace/BUILD.gn
index cb41004..7548894 100644
--- a/src/tracing/esp32_trace/BUILD.gn
+++ b/src/tracing/esp32_trace/BUILD.gn
@@ -20,6 +20,10 @@
   include_dirs = [ "include" ]
 }
 
+declare_args() {
+  matter_enable_esp_insights_system_stats = false
+}
+
 static_library("backend") {
   output_name = "libEsp32TracingBackend"
   output_dir = "${root_out_dir}/lib"
@@ -28,6 +32,17 @@
     "esp32_tracing.cpp",
     "esp32_tracing.h",
   ]
+  if (matter_enable_esp_insights_system_stats) {
+    sources += [
+      "insights_sys_stats.cpp",
+      "insights_sys_stats.h",
+    ]
+    deps = [
+      "${chip_root}/src/lib/core",
+      "${chip_root}/src/platform",
+      "${chip_root}/src/system",
+    ]
+  }
   public_deps = [ "${chip_root}/src/tracing" ]
 }
 
diff --git a/src/tracing/esp32_trace/insights_sys_stats.cpp b/src/tracing/esp32_trace/insights_sys_stats.cpp
new file mode 100644
index 0000000..128afc9
--- /dev/null
+++ b/src/tracing/esp32_trace/insights_sys_stats.cpp
@@ -0,0 +1,161 @@
+/*
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "insights_sys_stats.h"
+#include <esp_diagnostics_metrics.h>
+#include <esp_err.h>
+#include <esp_log.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <string.h>
+#include <system/SystemStats.h>
+
+namespace chip {
+namespace System {
+namespace Stats {
+
+InsightsSystemMetrics & InsightsSystemMetrics::GetInstance()
+{
+    static InsightsSystemMetrics instance;
+    return instance;
+}
+
+void InsightsSystemMetrics::SamplingHandler(Layer * systemLayer, void * context)
+{
+    auto instance            = static_cast<InsightsSystemMetrics *>(context);
+    count_t * highwatermarks = GetHighWatermarks();
+    for (int i = 0; i < System::Stats::kNumEntries; i++)
+    {
+        esp_err_t err = esp_diag_metrics_add_uint(instance->mLabels[i], static_cast<uint32_t>(highwatermarks[i]));
+        if (err != ESP_OK)
+        {
+            ESP_LOGE(kTag, "Failed to add the metric:%s, err:%d", instance->mLabels[i], err);
+        }
+    }
+    DeviceLayer::SystemLayer().StartTimer(instance->GetSamplingInterval(), SamplingHandler, instance);
+}
+
+CHIP_ERROR InsightsSystemMetrics::Unregister(intptr_t arg)
+{
+    InsightsSystemMetrics * instance = reinterpret_cast<InsightsSystemMetrics *>(arg);
+    if (!mRegistered)
+    {
+        return CHIP_ERROR_INCORRECT_STATE;
+    }
+    for (int i = 0; i < System::Stats::kNumEntries; i++)
+    {
+        if (mLabels[i] != nullptr)
+        {
+            esp_err_t err = esp_diag_metrics_unregister(mLabels[i]);
+            if (err != ESP_OK)
+            {
+                ESP_LOGE(kTag, "Failed to unregister metric:%s, err:%d", mLabels[i], err);
+            }
+            free(mLabels[i]);
+            mLabels[i] = nullptr;
+        }
+    }
+    mRegistered = false;
+    DeviceLayer::SystemLayer().CancelTimer(SamplingHandler, instance);
+    return CHIP_NO_ERROR;
+}
+
+void InsightsSystemMetrics::SetSamplingHandler(intptr_t arg)
+{
+    InsightsSystemMetrics * instance = reinterpret_cast<InsightsSystemMetrics *>(arg);
+
+    if (instance->mTimeout == System::Clock::kZero)
+    {
+        DeviceLayer::SystemLayer().CancelTimer(SamplingHandler, instance);
+    }
+    else
+    {
+        DeviceLayer::SystemLayer().CancelTimer(SamplingHandler, instance);
+        CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(instance->mTimeout, SamplingHandler, instance);
+        if (err != CHIP_NO_ERROR)
+        {
+            ESP_LOGE(kTag, "Failed to start the new timer %" CHIP_ERROR_FORMAT, err.Format());
+        }
+    }
+}
+
+CHIP_ERROR InsightsSystemMetrics::SetSamplingInterval(chip::System::Clock::Timeout aTimeout)
+{
+    if (!mRegistered)
+    {
+        return CHIP_ERROR_INCORRECT_STATE;
+    }
+    mTimeout = aTimeout;
+
+    return DeviceLayer::PlatformMgr().ScheduleWork(SetSamplingHandler, reinterpret_cast<intptr_t>(this));
+}
+
+CHIP_ERROR InsightsSystemMetrics::RegisterAndEnable(chip::System::Clock::Timeout aTimeout)
+{
+    if (mRegistered)
+    {
+        return CHIP_NO_ERROR;
+    }
+
+    if (aTimeout == System::Clock::kZero)
+    {
+        return CHIP_ERROR_INVALID_ARGUMENT;
+    }
+
+    const Label * labels = GetStrings();
+    for (int i = 0; i < System::Stats::kNumEntries; i++)
+    {
+        size_t labelLength = strlen(labels[i]);
+        if (labelLength >= kMaxStringLength)
+        {
+            labelLength = kMaxStringLength;
+            mLabels[i]  = strndup(labels[i], labelLength - 1);
+        }
+        else
+        {
+            mLabels[i] = strndup(labels[i], labelLength);
+        }
+
+        if (mLabels[i] == NULL)
+        {
+            Unregister(reinterpret_cast<intptr_t>(this));
+            return CHIP_ERROR_NO_MEMORY;
+        }
+
+        esp_err_t err = esp_diag_metrics_register(kTag, mLabels[i], labels[i], kPath, ESP_DIAG_DATA_TYPE_UINT);
+        if (err != ESP_OK)
+        {
+            ESP_LOGE(kTag, "Failed to register metric:%s, err:%d", mLabels[i], err);
+            Unregister(reinterpret_cast<intptr_t>(this));
+            return CHIP_ERROR_INCORRECT_STATE;
+        }
+    }
+
+    mTimeout = System::Clock::Milliseconds32(aTimeout);
+
+    CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(GetSamplingInterval(), SamplingHandler, this);
+    if (err != CHIP_NO_ERROR)
+    {
+        ESP_LOGE(kTag, "Failed to start the timer, err:%" CHIP_ERROR_FORMAT, err.Format());
+        return err;
+    }
+    mRegistered = true;
+    return CHIP_NO_ERROR;
+}
+
+} // namespace Stats
+} // namespace System
+} // namespace chip
diff --git a/src/tracing/esp32_trace/insights_sys_stats.h b/src/tracing/esp32_trace/insights_sys_stats.h
new file mode 100644
index 0000000..6d043b0
--- /dev/null
+++ b/src/tracing/esp32_trace/insights_sys_stats.h
@@ -0,0 +1,69 @@
+/*
+ *    Copyright (c) 2023 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <lib/core/CHIPError.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <system/SystemClock.h>
+#include <system/SystemStats.h>
+namespace chip {
+namespace System {
+namespace Stats {
+
+class InsightsSystemMetrics
+{
+public:
+    static InsightsSystemMetrics & GetInstance();
+
+    /*
+     * This api registers the system metrics to the insights and starts the
+     * timer to enable system stats periodically to the insights.
+     */
+    CHIP_ERROR RegisterAndEnable(chip::System::Clock::Timeout aTimeout);
+
+    /*
+     * This api unregisters the system stats which are registered
+     * as metrics to the esp-insights.
+     */
+    CHIP_ERROR Unregister(intptr_t arg);
+
+    /*
+     * This api cancels the timeout providing the user the flexibility
+     * to increase or decrease the frequency of sampling the System
+     * Stats. It cancels the timer if new timeout value is zero.
+     * If the value of timeout differs from existing value, then
+     * it cancels the previous timer and starts a new timer.
+     */
+    CHIP_ERROR SetSamplingInterval(chip::System::Clock::Timeout aTimeout);
+
+    System::Clock::Timeout GetSamplingInterval() { return mTimeout; }
+
+private:
+    InsightsSystemMetrics() {}
+    static constexpr int kMaxStringLength = 16;
+    bool mRegistered                      = false;
+    static constexpr char kPath[]         = "sys.mtr";
+    static constexpr char kTag[]          = "MTR";
+    System::Clock::Timeout mTimeout;
+    char * mLabels[chip::System::Stats::kNumEntries];
+
+    static void SamplingHandler(System::Layer * systemLayer, void * context);
+    static void SetSamplingHandler(intptr_t arg);
+};
+
+} // namespace Stats
+} // namespace System
+} // namespace chip