Skip to content
This repository has been archived by the owner on Apr 24, 2022. It is now read-only.

Commit

Permalink
implemented prometheus metrics endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
8-Lambda-8 committed Jan 2, 2022
1 parent ce52c74 commit 2a90a4b
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 1 deletion.
135 changes: 134 additions & 1 deletion libapicore/ApiServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ void ApiConnection::onRecvSocketDataCompleted(
}

// Do we support path ?
if (http_path != "/" && http_path != "/getstat1")
if (http_path != "/" && http_path != "/getstat1" && http_path != "/metrics")
{
std::string what =
"The requested resource " + http_path + " not found on this server";
Expand Down Expand Up @@ -858,6 +858,34 @@ void ApiConnection::onRecvSocketDataCompleted(
}
}

if (http_method == "GET" && (http_path == "/metrics"))
{
try
{
std::string body = getHttpMinerMetrics();
ss.clear();
ss << http_ver << " "
<< "200 Ok Error\r\n"
<< "Server: " << ethminer_get_buildinfo()->project_name_with_version
<< "\r\n"
<< "Content-Type: text/plain; charset=utf-8\r\n"
<< "Content-Length: " << body.size() << "\r\n\r\n"
<< body << "\r\n";
}
catch (const std::exception& _ex)
{
std::string what = "Internal error : " + std::string(_ex.what());
ss.clear();
ss << http_ver << " "
<< "500 Internal Server Error\r\n"
<< "Server: " << ethminer_get_buildinfo()->project_name_with_version
<< "\r\n"
<< "Content-Type: text/plain\r\n"
<< "Content-Length: " << what.size() << "\r\n\r\n"
<< what << "\r\n";
}
}

sendSocketData(ss.str(), true);
m_message.clear();
}
Expand Down Expand Up @@ -1194,6 +1222,111 @@ std::string ApiConnection::getHttpMinerStatDetail()
return _ret.str();
}

std::string ApiConnection::getHttpMinerMetrics()
{
Json::Value jStat = getMinerStatDetail();
uint64_t durationSeconds = jStat["host"]["runtime"].asUInt64();
std::string hostname = jStat["host"]["name"].asString();
std::string version = jStat["host"]["version"].asString();
std::string pool = jStat["connection"]["uri"].asString();

std::string help = "# HELP ";
std::string type = "# TYPE ";
std::string start = "ethminer_";

std::stringstream _ret;

// Info
_ret << help << start << "info Info of Miner Host." << std::endl;
_ret << type << start << "info gauge" << std::endl;
_ret << start << "info{hostname=\"" << hostname << "\",version=\""<< version << "\",pool=\""<< pool <<"\"} 1" << std::endl;

//Uptime
_ret << help << start << "uptime_sec Uptime of Miner in seconds." << std::endl;
_ret << type << start << "uptime_sec counter" << std::endl;
_ret << start << "uptime_sec " << to_string(durationSeconds) << std::endl;


//Device info
_ret << help << start << "device_info Info of Miner Devices." << std::endl;
_ret << type << start << "device_info gauge" << std::endl;
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
Json::Value device = jStat["devices"][i];
_ret << start << "device_info{id=\""<< to_string(i) <<"\",pci=\"" << device["hardware"]["pci"].asString() << "\",name=\""<< device["hardware"]["name"].asString() << "\",mode=\""<< device["_mode"].asString() <<"\",paused=\""<< device["mining"]["paused"].asBool() <<"\"} 1" << std::endl;
}

//Device hashrate
double total_hashrate = 0;
_ret << help << start << "hashrate Hashrate of Miner Devices." << std::endl;
_ret << type << start << "hashrate gauge" << std::endl;
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
Json::Value device = jStat["devices"][i];
double hashrate = std::stoul(device["mining"]["hashrate"].asString(), nullptr, 16);
total_hashrate += hashrate;
_ret << start << "hashrate{id=\""<< to_string(i) <<"\"} " << to_string(hashrate) << std::endl;
}

//Device Power
double total_power = 0;
_ret << help << start << "power Power of Miner Devices." << std::endl;
_ret << type << start << "power gauge" << std::endl;
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
Json::Value device = jStat["devices"][i];
double power = device["hardware"]["sensors"][2].asDouble();
total_power += power;
_ret << start << "power{id=\""<< to_string(i) <<"\"} " << to_string(power) << std::endl;
}

//Device Shares
unsigned int total_shares[] = {0, 0, 0};
_ret << help << start << "shares Shares of Miner Devices." << std::endl;
_ret << type << start << "shares counter" << std::endl;
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
Json::Value device = jStat["devices"][i];
uint shares[] = {device["mining"]["shares"][0].asUInt(), device["mining"]["shares"][1].asUInt(), device["mining"]["shares"][2].asUInt()};
total_shares[0] += shares[0];
total_shares[1] += shares[1];
total_shares[2] += shares[2];
_ret << start << "shares{state=\"accepted\",id=\""<< to_string(i) <<"\"} " << total_shares[0] << std::endl;
_ret << start << "shares{state=\"rejected\",id=\""<< to_string(i) <<"\"} " << total_shares[1] << std::endl;
_ret << start << "shares{state=\"failed\",id=\""<< to_string(i) <<"\"} " << total_shares[2] << std::endl;
}

//Device Temp
_ret << help << start << "temp of Miner Devices in °C." << std::endl;
_ret << type << start << "temp gauge" << std::endl;
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
Json::Value device = jStat["devices"][i];
_ret << start << "temp{id=\""<< to_string(i) <<"\"} " << device["hardware"]["sensors"][0].asString() << std::endl;
}
//Device Fan
_ret << help << start << "fan of Miner Devices in %." << std::endl;
_ret << type << start << "fan gauge" << std::endl;
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
Json::Value device = jStat["devices"][i];
_ret << start << "fan{id=\""<< to_string(i) <<"\"} " << device["hardware"]["sensors"][1].asString() << std::endl;
}

//Total hashrate
_ret << help << start << "hashrate_total Total Hashrate of Miner." << std::endl;
_ret << type << start << "hashrate_total gauge" << std::endl;
_ret << start << "hashrate_total " << total_hashrate << std::endl;

//Total power
_ret << help << start << "power_total Total Power of Miner." << std::endl;
_ret << type << start << "power_total gauge" << std::endl;
_ret << start << "power_total " << total_power << std::endl;

//Total shares
_ret << help << start << "shares_total Total Shares of Miner." << std::endl;
_ret << type << start << "shares_total counter" << std::endl;
_ret << start << "shares_total{state=\"accepted\"} " << total_shares[0] << std::endl;
_ret << start << "shares_total{state=\"rejected\"} " << total_shares[1] << std::endl;
_ret << start << "shares_total{state=\"failed\"} " << total_shares[2] << std::endl;

return _ret.str();
}

/**
* @brief Return a total and per GPU detailed list of current status
* As we return here difficulty and share counts (which are not getting resetted if we
Expand Down
2 changes: 2 additions & 0 deletions libapicore/ApiServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class ApiConnection

std::string getHttpMinerStatDetail();

std::string getHttpMinerMetrics();

Disconnected m_onDisconnected;

int m_sessionId;
Expand Down

0 comments on commit 2a90a4b

Please sign in to comment.