Files
fault_diagnosis/main.cpp

252 lines
9.2 KiB
C++

#include <string>
#include <yaml-cpp/yaml.h>
#include <filesystem>
#include <spdlog/spdlog.h>
#include <cpr/cpr.h>
#include <chrono>
#include <nlohmann/json.hpp>
#include <vector>
#include <cmath>
#include <cstdlib>
enum QUERIES {
INSTANT_QUERIES = 0,
RANGE_QUERIES = 1
};
double calculateMean(std::vector<double> vdata) {
double sum = 0.0;
for (auto const &iter: vdata) {
sum += iter;
}
return sum / vdata.size();
}
double calculateSD(std::vector<double> vdata) {
double mean, standardDeviation = 0.0;
mean = calculateMean(vdata);
for (auto const &iter: vdata) {
standardDeviation += pow(iter - mean, 2);
}
return sqrt(standardDeviation / vdata.size());
}
cpr::Response getValue(YAML::Node config, QUERIES queries, std::string strName = "") {
auto prometheus_url = config["prometheus address"].as<std::string>();
auto report_url = config["report address"].as<std::string>();
auto interval = config["interval"].as<int>();
auto range = config["time range"].as<int>() - 1;
auto job = config["job"].as<std::string>();
auto data = config["data"].as<std::string>();
spdlog::info("prometheus address : {}.", prometheus_url);
spdlog::info("report address : {}.", report_url);
spdlog::info("Interval of operation : {}s.", interval);
spdlog::info("time range : {}s.", range);
std::string str_query("{__name__=~\"");
if (strName == "") {
auto diagnosis = config["diagnosis"];
for (auto item: diagnosis) {
if (item.IsNull() || item["name"].IsNull()) {
continue;
}
auto name = item["name"].as<std::string>();
str_query.append(name);
str_query.append("|");
}
str_query.pop_back();
} else {
str_query.append(strName);
}
str_query.append("\",data=\"");
str_query.append(data);
str_query.append("\",job=\"");
str_query.append(job);
str_query.append("\"}");
spdlog::info("query: {}", str_query);
QUERIES promql = queries;
cpr::Response r;
if (promql == INSTANT_QUERIES) {
prometheus_url.append("/api/v1/query");
r = cpr::Get(
cpr::Url{prometheus_url},
cpr::Parameters{{"query", str_query}}
);
} else if (promql == RANGE_QUERIES) {
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
int64_t timepoint = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
prometheus_url.append("/api/v1/query_range");
r = cpr::Get(
cpr::Url{prometheus_url},
cpr::Parameters{{"query", str_query},
{"start", std::to_string(timepoint - range)},
{"end", std::to_string(timepoint)},
{"step", "1s"}}
);
}
return r;
}
int main(int argc, char *argv[]) {
spdlog::info("fault diagnosis");
std::string config_file_name = "./cfg.yml";
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 r = getValue(config, RANGE_QUERIES);
if (200 != r.status_code) {
spdlog::error("GET failed status_code: {}", r.status_code);
return EXIT_FAILURE;
}
spdlog::info("URL: {}", r.url.str());
//spdlog::info("Response text : {}", r.text);
nlohmann::json obj = nlohmann::json::parse(r.text.begin(), r.text.end(), nullptr, false);
std::vector<double> buff;
double SD = 0;
if (obj["status"] == "success") {
spdlog::info("query success");
auto d = obj["data"];
if (d.size() > 0) {
auto rt = d["resultType"];
auto r = d["result"];
if (rt == "matrix") {
if (r.size() > 0) {
for (auto res_iter: r) {
auto metric_name = res_iter["metric"]["__name__"];
spdlog::info("metric name {}", metric_name);
auto v = res_iter["values"];
if (v.size() > 0) {
buff.clear(); //清除缓冲数组
for (auto const &iter: v) {
if (iter.size() == 2) {
auto value = iter.at(1);
//spdlog::info("value: {}", value.get<std::string>());
double n = atof(value.get<std::string>().c_str());
//spdlog::info("value double: {}", n);
buff.push_back(n);
} else {
spdlog::error("values size error");
return EXIT_FAILURE;
}
}
///计算标准差-1的绝对值
// SD = calculateSD(buff);
// spdlog::info("mean: {}", calculateMean(buff));
// spdlog::info("standard deviation: {}", SD);
// if (fabs(SD - 1) == 0 || fabs(SD - 1) > 1) {
// spdlog::error("{} alert", metric_name);
// }
auto r1 = getValue(config, INSTANT_QUERIES, metric_name);
if (200 != r1.status_code) {
spdlog::error("GET failed status_code: {}", r1.status_code);
return EXIT_FAILURE;
}
spdlog::warn("r1 URL: {}", r1.url.str());
spdlog::warn("r1 Response text : {}", r1.text);
nlohmann::json obj1 = nlohmann::json::parse(r1.text.begin(), r1.text.end(), nullptr, false);
if (obj1["status"] == "success") {
spdlog::warn("query success");
auto d1 = obj1["data"];
if (d1.size() > 0) {
auto rt1 = d1["resultType"];
auto re1 = d1["result"];
if (rt1 == "vector") {
if (re1.size() == 1) {
auto metric_name1 = re1.at(0)["metric"]["__name__"];
spdlog::warn("metric name {}", metric_name1);
auto v1 = re1.at(0)["value"];
if (v1.size() == 2) {
auto value1 = v1.at(1);
double n1 = atof(value1.get<std::string>().c_str());
SD = calculateSD(buff);
spdlog::info("mean: {}", calculateMean(buff));
spdlog::info("standard deviation: {}", SD);
spdlog::warn("value double: {}", n1);
spdlog::warn("new value : {}",(n1-calculateMean(buff))/SD);
}
} else {
spdlog::error("no result");
return EXIT_FAILURE;
}
} else {
spdlog::error("resultType not vector");
return EXIT_FAILURE;
}
} else {
spdlog::error("no data");
return EXIT_FAILURE;
}
} else {
spdlog::error("query false");
return EXIT_FAILURE;
}
} else {
spdlog::error("no values");
return EXIT_FAILURE;
}
}
} else {
spdlog::error("no result");
return EXIT_FAILURE;
}
} else {
spdlog::error("resultType not matrix");
return EXIT_FAILURE;
}
} else {
spdlog::error("no data");
return EXIT_FAILURE;
}
} else {
spdlog::error("query false");
return EXIT_FAILURE;
}
// spdlog::info("json dump: {}", obj["data"]["result"].dump());
// nlohmann::json j = obj["data"]["result"].at(0);
// spdlog::info("json values size: {}", j["values"].size());
// for (auto const &iter: j["values"]) {
// if (iter.size() == 2) {
// spdlog::info("value: {}",iter.at(1));
// }
// }
return 0;
}