Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Erweiterung Prometheus EP #615

Closed
fsck-block opened this issue Jan 21, 2023 · 5 comments
Closed

Feature Request: Erweiterung Prometheus EP #615

fsck-block opened this issue Jan 21, 2023 · 5 comments
Assignees
Labels
enhancement New feature or request fixed dev fixed

Comments

@fsck-block
Copy link
Contributor

Hallo

ich habe eine Erweiterung für die Channel Daten bei den Prometheus Metrics (ENABLE_PROMETHEUS_EP).

Wie kann ich das Code Fragment am besten beisteuern?

Gruß

@lumapu
Copy link
Owner

lumapu commented Jan 21, 2023

am schönsten per Pull-Request. Dafür musst du einiges machen

  • einen fork von meinem Repository machen
  • deinen fork lokal auschecken
  • Änderungen machen
  • Änderungen committen
  • Pull Request erstellen auf meinen development03 Branch

oder quick 'n dirty einfach hier reinposten (mit drei backticks ` vor und nach dem Code)

@fsck-block
Copy link
Contributor Author

Mit fork und pull request über unterschiedliche branches bin ich wohl etwas überfordert.
Der Vergleich sieht irgendwie komisch aus. Also erst ein mal quick 'n dirty

#ifdef ENABLE_PROMETHEUS_EP
        void showMetrics(AsyncWebServerRequest *request) {
            DPRINTLN(DBG_VERBOSE, F("web::showMetrics"));
            String metrics;
            char infoline[90];

            // System info
            snprintf(infoline, sizeof(infoline), "ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1", mApp->getVersion(), mConfig->sys.deviceName);
            metrics += "# TYPE ahoy_solar_info gauge\n" + String(infoline) + "\n";
            Inverter<> *iv;
            record_t<> *rec;
            char type[60], topic[80], val[25];
            for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
                iv = mSys->getInverterByPos(id);
                if(NULL == iv)
                    continue;
                // Inverter info
                snprintf(infoline, sizeof(infoline), "ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\",enabled=\"%d\"} 1",
                    iv->config->name, iv->config->serial.u64,iv->config->enabled);
                metrics += "# TYPE ahoy_solar_inverter_info gauge\n" + String(infoline) + "\n";

                // AC
                rec = iv->getRecordStruct(RealTimeRunData_Debug);
                for(uint8_t i = 0; i < rec->length; i++) {
                    uint8_t channel = rec->assign[i].ch;
                    if(channel == 0) {
                        String promUnit, promType;
                        std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(i, rec));
                        snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s_%s %s", iv->getFieldName(i, rec), promUnit.c_str(), promType.c_str());
                        snprintf(topic, sizeof(topic), "ahoy_solar_%s_%s{inverter=\"%s\"}", iv->getFieldName(i, rec), promUnit.c_str(), iv->config->name);
                        snprintf(val, sizeof(val), "%.3f", iv->getValue(i, rec));
                        metrics += String(type) + "\n" + String(topic) + " " + String(val) + "\n";
                    }
                }
                // channels DC
                for(uint8_t j = 1; j <= iv->channels; j ++) {
                    uint8_t pos;
                    for (uint8_t k = 0; k < 6; k++) {
                        switch(k) {
                            default: pos = (iv->getPosByChFld(j, FLD_UDC, rec)); break;
                            case 1:  pos = (iv->getPosByChFld(j, FLD_IDC, rec)); break;
                            case 2:  pos = (iv->getPosByChFld(j, FLD_PDC, rec)); break;
                            case 3:  pos = (iv->getPosByChFld(j, FLD_YD, rec));  break;
                            case 4:  pos = (iv->getPosByChFld(j, FLD_YT, rec));  break;
                            case 5:  pos = (iv->getPosByChFld(j, FLD_IRR, rec)); break;
                        }
                        String promUnit, promType;
                        std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(pos, rec));
                        snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s_%s %s", iv->getFieldName(pos, rec), promUnit.c_str(), promType.c_str());
                        snprintf(topic, sizeof(topic), "ahoy_solar_%s_%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(pos, rec), promUnit.c_str(), iv->config->name, iv->config->chName[j-1]);
                        snprintf(val, sizeof(val), "%.3f", iv->getValue(pos, rec));
                        metrics += String(type) + "\n" + String(topic) + " " + String(val) + "\n";
                    }
                }
            }

            // NRF Statistics
            statistics_t *stat = mApp->getStatistics();
            metrics += radioStatistic(F("rx_success"),     stat->rxSuccess);
            metrics += radioStatistic(F("rx_fail"),        stat->rxFail);
            metrics += radioStatistic(F("rx_fail_answer"), stat->rxFailNoAnser);
            metrics += radioStatistic(F("frame_cnt"),      stat->frmCnt);
            metrics += radioStatistic(F("tx_cnt"),         mSys->Radio.mSendCnt);

            AsyncWebServerResponse *response = request->beginResponse(200, F("text/plain"), metrics);
            request->send(response);
        }

        String radioStatistic(String statistic, uint32_t value) {
            char type[60], topic[80], val[25];
            snprintf(type, sizeof(type), "# TYPE ahoy_solar_radio_%s gauge",statistic.c_str());
            snprintf(topic, sizeof(topic), "ahoy_solar_radio_%s",statistic.c_str());
            snprintf(val, sizeof(val), "%d", value);
            return ( String(type) + "\n" + String(topic) + " " + String(val) + "\n");
        }

        std::pair<String, String> convertToPromUnits(String shortUnit) {
            if(shortUnit == "A")    return {"ampere", "gauge"};
            if(shortUnit == "V")    return {"volt", "gauge"};
            if(shortUnit == "%")    return {"ratio", "gauge"};
            if(shortUnit == "W")    return {"watt", "gauge"};
            if(shortUnit == "Wh")   return {"watt_daily", "counter"};
            if(shortUnit == "kWh")  return {"watt_total", "counter"};
            if(shortUnit == "°C")   return {"celsius", "gauge"};

            return {"", "gauge"};
        }
#endif

@lumapu
Copy link
Owner

lumapu commented Jan 22, 2023

danke für den Code, ich werde ihn die Tage einpflegen

@stefan123t stefan123t added the enhancement New feature or request label Jan 22, 2023
@stefan123t stefan123t changed the title Erweiterung Prometheus EP Feature Request: Erweiterung Prometheus EP Jan 22, 2023
lumapu added a commit that referenced this issue Jan 25, 2023
…er) #620

added rotate display feature #619
improved Prometheus endpoint #615, thx to fsck-block
@lumapu lumapu self-assigned this Jan 28, 2023
@lumapu lumapu added the fixed dev fixed label Jan 28, 2023
@fsck-block
Copy link
Contributor Author

Hallo Lukas

beim Zusammenschreiben der verfügbaren Prometheus Metriken habe ich eine Konfiguration mit mehreren Invertern ausprobiert.
Und siehe da, der Code funktioniert nicht.

  1. Da alle Metriken incl. Beschreibung als einzelner String zusammengesetzt werden führt dies bei vielen Invertern schon mal zu Speicherproblemen
  2. Aber auch schon bei zwei Invertern passt das alles nicht mehr in eine Übertragung (des AsyncWebServer).
    Und dann gibt es ein kleines use-after-free problem mit dem zusammengebauten String.

Schlussendlich habe ich das ganze auf "Chunked Response" umgestellt. Ein bischen tricky da man zwei verschachtelte Schleifen über mehrere asyncrone Aufrufe abarbeiten muss.

Der Code läuft bei mir gerade im Testbetrieb und wenn es für dich in Ordnung ist würde ich es diesmal mit einem Pull-Request probieren.

@lumapu
Copy link
Owner

lumapu commented Jan 29, 2023

perfekt, danke für dein mitwirken. Habe gestern mal wieder an den ähnlichen Problem in Mqtt gearbeitet 🙈

lumapu added a commit that referenced this issue Mar 9, 2023
improved saving settings of display #747, #746
disabled contrast for Nokia display #746
added Prometheus as compile option #719, #615
update MQTT lib to v1.4.1
limit decimal places to 2 in `live`
added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657
a `max-module-power` of `0` disables channel in live view `setup`
@lumapu lumapu closed this as completed Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request fixed dev fixed
Projects
None yet
Development

No branches or pull requests

3 participants