#include #include #include #include #include #include #include #include #include #include #include "client/client.h" #include "collector/collector.h" class MetricsHandle : public CivetHandler { public: explicit MetricsHandle(std::shared_ptr coll) : coll_(coll) { } bool handleGet(CivetServer *server, struct mg_connection *conn) override { std::string json = to_string(coll_->getMetricsJson()); mg_send_http_ok(conn, "application/json", json.size()); mg_write(conn, json.c_str(), json.size()); return true; } private: std::shared_ptr coll_; }; class SimulationHandle : public CivetHandler { public: explicit SimulationHandle(std::shared_ptr coll) : coll_(coll) { } bool handleGet(CivetServer *server, struct mg_connection *conn) override { auto name = getMetric(conn); auto context = to_string(coll_->simulationConfig(name)); mg_send_http_ok(conn, "application/json", context.size()); mg_write(conn, context.c_str(), context.size()); return true; } bool handlePost(CivetServer *server, struct mg_connection *conn) override { auto name = getMetric(conn); auto json = getPostJson(conn); coll_->setSimulationConfig(name, json); mg_send_http_ok(conn, "application/json", 0); return true; } protected: std::string getMetric(mg_connection *conn) { const struct mg_request_info *req_info = mg_get_request_info(conn); if (nullptr != req_info->query_string) { return req_info->query_string; } return {}; } nlohmann::json getPostJson(mg_connection *conn) { const struct mg_request_info *req_info = mg_get_request_info(conn); auto size = req_info->content_length + 1; char *buff = new char[size]; mg_read(conn, buff, size); auto ret = nlohmann::json::parse(buff, buff + size - 1, nullptr, false); delete[] buff; return ret; } private: std::shared_ptr coll_; }; int main(int argc, char *argv[]) { mg_init_library(0); spdlog::info("OPC-UA Exporter"); std::string config_file_name = "./opcua.yml"; #ifdef Debug spdlog::set_level(spdlog::level::trace); #endif if (2 == argc) { config_file_name = argv[1]; } if (!std::filesystem::exists(config_file_name)) { spdlog::error("the config file({}) not exists.", config_file_name); return EXIT_FAILURE; } YAML::Node config = YAML::LoadFile(config_file_name); auto exposer_bind_addr = config["exposer"]["bind"].as("0.0.0.0:8090"); auto exposer_thread_num = config["exposer"]["thread"].as(2); spdlog::info("exposer bind addr : {}", exposer_bind_addr); spdlog::info("exposer thread number : {}", exposer_thread_num); prometheus::Exposer exposer{exposer_bind_addr, exposer_thread_num}; std::vector civetOptions = { {"listening_ports"}, {config["api"]["port"].as("8080")} }; CivetServer webServer(civetOptions); auto ua_edp = config["opcua"]["endpoint"].as(); if (ua_edp.empty()) { spdlog::error("the opc ua endpoint not exists."); return EXIT_FAILURE; } auto ua_client = std::make_shared(ua_edp); auto opc_collector = std::make_shared(config["metrics"], ua_client); exposer.RegisterCollectable(opc_collector); auto metricsHandle = MetricsHandle(opc_collector); auto simulationHandle = SimulationHandle(opc_collector); webServer.addHandler( "/api/metrics", metricsHandle ); webServer.addHandler( "/api/simulate", simulationHandle ); ua_client->run(); return 0; }