[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