Metrics.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
  2. #include "Metrics.h"
  3. #include "Batch.h"
  4. #include "esp_event.h"
  5. #include "esp_log.h"
  6. #include "esp_netif.h"
  7. #include "esp_ota_ops.h"
  8. #include "esp_system.h"
  9. #include "esp_tls.h"
  10. #include "freertos/FreeRTOS.h"
  11. #include "freertos/task.h"
  12. #include "nvs_flash.h"
  13. #include "tools.h"
  14. #include <cstdarg>
  15. #include <cstdio>
  16. #include <ctype.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <vector>
  20. #include "cJSON.h"
  21. #include "freertos/timers.h"
  22. #include "network_manager.h"
  23. #include "platform_config.h"
  24. static const char* TAG = "metrics";
  25. #if CONFIG_WITH_METRICS
  26. extern bool is_network_connected();
  27. #define METRICS_CLIENT_ID_LEN 50
  28. #define MAX_HTTP_RECV_BUFFER 512
  29. static bool metrics_usage_gen = false;
  30. static uint32_t metrics_usage_gen_time = 0;
  31. #ifndef METRICS_API_KEY
  32. #pragma message "Metrics API key needs to be passed from the environment"
  33. #define METRICS_API_KEY "ZZZ"
  34. #endif
  35. static const char* metrics_api_key =
  36. static const char* parms_str = "params";
  37. static const char* properties_str = "properties";
  38. static const char* user_properties_str = "user_properties";
  39. static const char* items_str = "items";
  40. static const char* quantity_str = "quantity";
  41. static const char* metrics_url = "https://app.posthog.com";
  42. static TimerHandle_t timer;
  43. extern cJSON* get_cmd_list();
  44. Metrics::Batch batch;
  45. static void metrics_timer_cb(void* timer_id) {
  46. if (batch.has_events()) {
  47. if (!is_network_connected()) {
  48. ESP_LOGV(TAG, "Network not connected. can't flush");
  49. } else {
  50. ESP_LOGV(TAG, "Pushing events");
  51. batch.push();
  52. }
  53. }
  54. if (gettime_ms() > metrics_usage_gen_time && !metrics_usage_gen) {
  55. metrics_usage_gen = true;
  56. ESP_LOGV(TAG, "Generate command list to pull features");
  57. cJSON* cmdlist = get_cmd_list();
  58. dump_json_content("generated cmd list", cmdlist, ESP_LOG_VERBOSE);
  59. cJSON_Delete(cmdlist);
  60. }
  61. }
  62. void metrics_init() {
  63. ESP_LOGV(TAG, "Initializing metrics");
  64. batch.configure(metrics_api_key, metrics_url);
  65. if (!timer) {
  66. ESP_LOGE(TAG, "Metrics Timer failure");
  67. } else {
  68. ESP_LOGV(TAG, "Starting timer");
  69. xTimerStart(timer, portMAX_DELAY);
  70. }
  71. // set a 20 seconds delay before generating the
  72. // features so the system has time to boot
  73. metrics_usage_gen_time = gettime_ms() + 20000;
  74. }
  75. void metrics_event_playback(const char* source) {
  76. ESP_LOGV(TAG, "Playback event: %s", source);
  77. auto event = batch.add_event("play").add_property("source", source);
  78. }
  79. void metrics_event_boot(const char* partition) {
  80. ESP_LOGV(TAG, "Boot event %s", partition);
  81. auto event = batch.add_event("start");
  82. event.add_property("partition", partition);
  83. }
  84. void metrics_add_feature_variant(const char* name, const char* format, ...) {
  85. va_list args;
  86. ESP_LOGV(TAG, "Feature %s", name);
  87. va_start(args, format);
  88. // Determine the required buffer size
  89. int size = vsnprintf(nullptr, 0, format, args);
  90. va_end(args); // Reset the va_list
  91. // Allocate buffer and format the string
  92. std::vector<char> buffer(size + 1); // +1 for the null-terminator
  93. va_start(args, format);
  94. vsnprintf(buffer.data(), buffer.size(), format, args);
  95. va_end(args);
  96. // Now buffer.data() contains the formatted string
  97. batch.add_feature_variant_event(name, buffer.data());
  98. }
  99. void metrics_add_feature(const char* name, bool active) {
  100. ESP_LOGV(TAG, "Adding feature %s: %s", name, active ? "ACTIVE" : "INACTIVE");
  101. batch.add_remove_feature_event(name, active);
  102. }
  103. void metrics_event(const char* name) {
  104. ESP_LOGV(TAG, "Adding Event %s", name);
  105. batch.add_event(name);
  106. }
  107. #else
  108. static const char * not_enabled = " - (metrics not enabled, this is just marking where the call happens)";
  109. void metrics_init(){
  110. #pragma message("Metrics disabled")
  111. ESP_LOGD(TAG,"Metrics init%s",not_enabled);
  112. }
  113. void metrics_event_boot(const char* partition){
  114. ESP_LOGD(TAG,"Metrics Event Boot from partition %s%s",partition,not_enabled);
  115. }
  116. void metrics_event(const char* name){
  117. ESP_LOGD(TAG,"Metrics Event %s%s",name,not_enabled);
  118. }
  119. void metrics_add_feature(const char* name, bool active) {
  120. ESP_LOGD(TAG,"Metrics add feature %s%s%s",name,active?"ACTIVE":"INACTIVE",not_enabled);
  121. }
  122. void metrics_add_feature_variant(const char* name, const char* format, ...){
  123. va_list args;
  124. ESP_LOGV(TAG, "Feature %s", name);
  125. va_start(args, format);
  126. // Determine the required buffer size
  127. int size = vsnprintf(nullptr, 0, format, args);
  128. va_end(args); // Reset the va_list
  129. // Allocate buffer and format the string
  130. std::vector<char> buffer(size + 1); // +1 for the null-terminator
  131. va_start(args, format);
  132. vsnprintf(buffer.data(), buffer.size(), format, args);
  133. va_end(args);
  134. ESP_LOGD(TAG,"Metrics add feature %s variant %s%s",name,buffer.data(),not_enabled);
  135. }
  136. #endif