openmetrics.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include "openmetrics.h"
  2. #include "functional"
  3. #include "esp_log.h"
  4. /**
  5. * create a singe metric from the given input
  6. **/
  7. std::string createMetric(const std::string &metricName, const std::string &help, const std::string &type, const std::string &value)
  8. {
  9. return "# HELP " + metricName + " " + help + "\n" +
  10. "# TYPE " + metricName + " " + type + "\n" +
  11. metricName + " " + value + "\n";
  12. }
  13. typedef struct sequence_metric {
  14. const char *name;
  15. const char *help;
  16. const char *type;
  17. std::function<std::string(NumberPost *number)> valueFunc;
  18. } sequence_metric_t;
  19. sequence_metric_t sequenceMetrics[4] = {
  20. { "flow_value", "current value of meter readout", "gauge", [](NumberPost *number)-> std::string {return number->ReturnValue;} },
  21. { "flow_raw_value", "current raw value of meter readout", "gauge", [](NumberPost *number)-> std::string {return number->ReturnRawValue;} },
  22. { "flow_pre_value", "previous value of meter readout", "gauge", [](NumberPost *number)-> std::string {return number->ReturnPreValue;} },
  23. { "flow_error", "Error message text != 'no error'", "gauge", [](NumberPost *number)-> std::string {return number->ErrorMessageText.compare("no error") == 0 ? "0" : "1";} },
  24. };
  25. std::string createSequenceMetrics(std::string prefix, const std::vector<NumberPost *> &numbers)
  26. {
  27. std::string result;
  28. for (int i = 0; i<sizeof(sequenceMetrics)/sizeof(sequence_metric_t);i++)
  29. {
  30. std::string res;
  31. for (const auto &number : numbers)
  32. {
  33. std::string value = sequenceMetrics[i].valueFunc(number);
  34. if (value.find("N") != std::string::npos) {
  35. value = "NaN";
  36. }
  37. ESP_LOGD("METRICS", "metric=%s, name=%s, value = %s ",sequenceMetrics[i].name,number->name.c_str(), value.c_str());
  38. // only valid data is reported (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#missing-data)
  39. if (value.length() > 0)
  40. {
  41. auto label = number->name;
  42. // except newline, double quote, and backslash (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#abnf)
  43. // to keep it simple, these characters are just removed from the label
  44. replaceAll(label, "\\", "");
  45. replaceAll(label, "\"", "");
  46. replaceAll(label, "\n", "");
  47. res += prefix + "_" + sequenceMetrics[i].name + "{sequence=\"" + label + "\"} " + value + "\n";
  48. }
  49. }
  50. // prepend metadata if a valid metric was created
  51. if (res.length() > 0)
  52. {
  53. res = "# HELP " + prefix + "_" + sequenceMetrics[i].name + " " + sequenceMetrics[i].help + "\n"
  54. + "# TYPE " + prefix + "_" + sequenceMetrics[i].name + " " + sequenceMetrics[i].type + "\n"
  55. + res;
  56. }
  57. result += res;
  58. }
  59. return result;
  60. }
  61. /**
  62. * Generate the MetricFamily from all available sequences
  63. * @returns the string containing the text wire format of the MetricFamily
  64. **/
  65. /*
  66. std::string createSequenceMetrics(std::string prefix, const std::vector<NumberPost *> &numbers)
  67. {
  68. std::string res;
  69. for (const auto &number : numbers)
  70. {
  71. // only valid data is reported (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#missing-data)
  72. if (number->ReturnValue.length() > 0)
  73. {
  74. auto label = number->name;
  75. // except newline, double quote, and backslash (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#abnf)
  76. // to keep it simple, these characters are just removed from the label
  77. replaceAll(label, "\\", "");
  78. replaceAll(label, "\"", "");
  79. replaceAll(label, "\n", "");
  80. res += prefix + "_flow_value{sequence=\"" + label + "\"} " + number->ReturnValue + "\n";
  81. }
  82. }
  83. // prepend metadata if a valid metric was created
  84. if (res.length() > 0)
  85. {
  86. res = "# HELP " + prefix + "_flow_value current value of meter readout\n# TYPE " + prefix + "_flow_value gauge\n" + res;
  87. }
  88. return res;
  89. }
  90. */