openmetrics.cpp 4.2 KB

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