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

Commit 2a90a4b

Browse files
committed
implemented prometheus metrics endpoint
1 parent ce52c74 commit 2a90a4b

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

libapicore/ApiServer.cpp

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ void ApiConnection::onRecvSocketDataCompleted(
805805
}
806806

807807
// Do we support path ?
808-
if (http_path != "/" && http_path != "/getstat1")
808+
if (http_path != "/" && http_path != "/getstat1" && http_path != "/metrics")
809809
{
810810
std::string what =
811811
"The requested resource " + http_path + " not found on this server";
@@ -858,6 +858,34 @@ void ApiConnection::onRecvSocketDataCompleted(
858858
}
859859
}
860860

861+
if (http_method == "GET" && (http_path == "/metrics"))
862+
{
863+
try
864+
{
865+
std::string body = getHttpMinerMetrics();
866+
ss.clear();
867+
ss << http_ver << " "
868+
<< "200 Ok Error\r\n"
869+
<< "Server: " << ethminer_get_buildinfo()->project_name_with_version
870+
<< "\r\n"
871+
<< "Content-Type: text/plain; charset=utf-8\r\n"
872+
<< "Content-Length: " << body.size() << "\r\n\r\n"
873+
<< body << "\r\n";
874+
}
875+
catch (const std::exception& _ex)
876+
{
877+
std::string what = "Internal error : " + std::string(_ex.what());
878+
ss.clear();
879+
ss << http_ver << " "
880+
<< "500 Internal Server Error\r\n"
881+
<< "Server: " << ethminer_get_buildinfo()->project_name_with_version
882+
<< "\r\n"
883+
<< "Content-Type: text/plain\r\n"
884+
<< "Content-Length: " << what.size() << "\r\n\r\n"
885+
<< what << "\r\n";
886+
}
887+
}
888+
861889
sendSocketData(ss.str(), true);
862890
m_message.clear();
863891
}
@@ -1194,6 +1222,111 @@ std::string ApiConnection::getHttpMinerStatDetail()
11941222
return _ret.str();
11951223
}
11961224

1225+
std::string ApiConnection::getHttpMinerMetrics()
1226+
{
1227+
Json::Value jStat = getMinerStatDetail();
1228+
uint64_t durationSeconds = jStat["host"]["runtime"].asUInt64();
1229+
std::string hostname = jStat["host"]["name"].asString();
1230+
std::string version = jStat["host"]["version"].asString();
1231+
std::string pool = jStat["connection"]["uri"].asString();
1232+
1233+
std::string help = "# HELP ";
1234+
std::string type = "# TYPE ";
1235+
std::string start = "ethminer_";
1236+
1237+
std::stringstream _ret;
1238+
1239+
// Info
1240+
_ret << help << start << "info Info of Miner Host." << std::endl;
1241+
_ret << type << start << "info gauge" << std::endl;
1242+
_ret << start << "info{hostname=\"" << hostname << "\",version=\""<< version << "\",pool=\""<< pool <<"\"} 1" << std::endl;
1243+
1244+
//Uptime
1245+
_ret << help << start << "uptime_sec Uptime of Miner in seconds." << std::endl;
1246+
_ret << type << start << "uptime_sec counter" << std::endl;
1247+
_ret << start << "uptime_sec " << to_string(durationSeconds) << std::endl;
1248+
1249+
1250+
//Device info
1251+
_ret << help << start << "device_info Info of Miner Devices." << std::endl;
1252+
_ret << type << start << "device_info gauge" << std::endl;
1253+
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
1254+
Json::Value device = jStat["devices"][i];
1255+
_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;
1256+
}
1257+
1258+
//Device hashrate
1259+
double total_hashrate = 0;
1260+
_ret << help << start << "hashrate Hashrate of Miner Devices." << std::endl;
1261+
_ret << type << start << "hashrate gauge" << std::endl;
1262+
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
1263+
Json::Value device = jStat["devices"][i];
1264+
double hashrate = std::stoul(device["mining"]["hashrate"].asString(), nullptr, 16);
1265+
total_hashrate += hashrate;
1266+
_ret << start << "hashrate{id=\""<< to_string(i) <<"\"} " << to_string(hashrate) << std::endl;
1267+
}
1268+
1269+
//Device Power
1270+
double total_power = 0;
1271+
_ret << help << start << "power Power of Miner Devices." << std::endl;
1272+
_ret << type << start << "power gauge" << std::endl;
1273+
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
1274+
Json::Value device = jStat["devices"][i];
1275+
double power = device["hardware"]["sensors"][2].asDouble();
1276+
total_power += power;
1277+
_ret << start << "power{id=\""<< to_string(i) <<"\"} " << to_string(power) << std::endl;
1278+
}
1279+
1280+
//Device Shares
1281+
unsigned int total_shares[] = {0, 0, 0};
1282+
_ret << help << start << "shares Shares of Miner Devices." << std::endl;
1283+
_ret << type << start << "shares counter" << std::endl;
1284+
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
1285+
Json::Value device = jStat["devices"][i];
1286+
uint shares[] = {device["mining"]["shares"][0].asUInt(), device["mining"]["shares"][1].asUInt(), device["mining"]["shares"][2].asUInt()};
1287+
total_shares[0] += shares[0];
1288+
total_shares[1] += shares[1];
1289+
total_shares[2] += shares[2];
1290+
_ret << start << "shares{state=\"accepted\",id=\""<< to_string(i) <<"\"} " << total_shares[0] << std::endl;
1291+
_ret << start << "shares{state=\"rejected\",id=\""<< to_string(i) <<"\"} " << total_shares[1] << std::endl;
1292+
_ret << start << "shares{state=\"failed\",id=\""<< to_string(i) <<"\"} " << total_shares[2] << std::endl;
1293+
}
1294+
1295+
//Device Temp
1296+
_ret << help << start << "temp of Miner Devices in °C." << std::endl;
1297+
_ret << type << start << "temp gauge" << std::endl;
1298+
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
1299+
Json::Value device = jStat["devices"][i];
1300+
_ret << start << "temp{id=\""<< to_string(i) <<"\"} " << device["hardware"]["sensors"][0].asString() << std::endl;
1301+
}
1302+
//Device Fan
1303+
_ret << help << start << "fan of Miner Devices in %." << std::endl;
1304+
_ret << type << start << "fan gauge" << std::endl;
1305+
for (Json::Value::ArrayIndex i = 0; i != jStat["devices"].size(); i++){
1306+
Json::Value device = jStat["devices"][i];
1307+
_ret << start << "fan{id=\""<< to_string(i) <<"\"} " << device["hardware"]["sensors"][1].asString() << std::endl;
1308+
}
1309+
1310+
//Total hashrate
1311+
_ret << help << start << "hashrate_total Total Hashrate of Miner." << std::endl;
1312+
_ret << type << start << "hashrate_total gauge" << std::endl;
1313+
_ret << start << "hashrate_total " << total_hashrate << std::endl;
1314+
1315+
//Total power
1316+
_ret << help << start << "power_total Total Power of Miner." << std::endl;
1317+
_ret << type << start << "power_total gauge" << std::endl;
1318+
_ret << start << "power_total " << total_power << std::endl;
1319+
1320+
//Total shares
1321+
_ret << help << start << "shares_total Total Shares of Miner." << std::endl;
1322+
_ret << type << start << "shares_total counter" << std::endl;
1323+
_ret << start << "shares_total{state=\"accepted\"} " << total_shares[0] << std::endl;
1324+
_ret << start << "shares_total{state=\"rejected\"} " << total_shares[1] << std::endl;
1325+
_ret << start << "shares_total{state=\"failed\"} " << total_shares[2] << std::endl;
1326+
1327+
return _ret.str();
1328+
}
1329+
11971330
/**
11981331
* @brief Return a total and per GPU detailed list of current status
11991332
* As we return here difficulty and share counts (which are not getting resetted if we

libapicore/ApiServer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class ApiConnection
5252

5353
std::string getHttpMinerStatDetail();
5454

55+
std::string getHttpMinerMetrics();
56+
5557
Disconnected m_onDisconnected;
5658

5759
int m_sessionId;

0 commit comments

Comments
 (0)