@@ -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
0 commit comments