Merge pull request #5 from nilsding/add-prometheus-metrics

Add /metrics endpoint which can be used with Prometheus
This commit is contained in:
bdring
2019-11-03 18:59:30 -06:00
committed by GitHub
3 changed files with 137 additions and 92 deletions

View File

@@ -1196,7 +1196,6 @@ void getInput(){
// -------------- SFX -------------- // -------------- SFX --------------
// --------------------------------- // ---------------------------------
/*
/* /*
This is used sweep across (up or down) a frequency range for a specified duration. This is used sweep across (up or down) a frequency range for a specified duration.
A sin based warble is added to the frequency. This function is meant to be called A sin based warble is added to the frequency. This function is meant to be called

View File

@@ -64,6 +64,8 @@
#define MIN_REDRAW_INTERVAL 1000.0 / 60.0 // divide by frames per second..if you tweak adjust player speed #define MIN_REDRAW_INTERVAL 1000.0 / 60.0 // divide by frames per second..if you tweak adjust player speed
#endif #endif
// Comment or remove the next #define to disable the /metrics endpoint on the HTTP server.
// This endpoint provides the Twang32 stats for ingestion via Prometheus.
#define ENABLE_PROMETHEUS_METRICS_ENDPOINT
#endif #endif

View File

@@ -9,7 +9,14 @@ WiFiServer server(80);
char linebuf[80]; char linebuf[80];
int charcount=0; int charcount=0;
enum PAGE_TO_SEND
{
Stats,
Metrics
};
void ap_setup() { void ap_setup() {
bool ret; bool ret;
@@ -30,129 +37,166 @@ void ap_setup() {
Serial.println(passphrase); Serial.println(passphrase);
Serial.println("Web Server Address: http://192.168.4.1"); Serial.println("Web Server Address: http://192.168.4.1");
}
}
void sendStatsPage(WiFiClient client) { void sendStatsPage(WiFiClient client) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line: // and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK"); client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html"); client.println("Content-type:text/html");
client.println(); client.println();
client.println("<html>"); client.println("<html>");
client.println("<body>"); client.println("<body>");
client.println("<h1>TWANG32 Play Stats</h1>"); client.println("<h1>TWANG32 Play Stats</h1>");
client.println("<ul>"); client.println("<ul>");
client.print("<li>Games played: "); client.print(user_settings.games_played); client.println("</li>");
client.print("<li>Games played: "); client.print(user_settings.games_played); client.println("</li>"); if (user_settings.games_played > 0) { // prevent divide by 0
if (user_settings.games_played > 0) { // prevent divide by 0
client.print("<li>Average score: "); client.print(user_settings.total_points / user_settings.games_played); client.println("</li>"); client.print("<li>Average score: "); client.print(user_settings.total_points / user_settings.games_played); client.println("</li>");
} }
client.print("<li>High score: "); client.print(user_settings.high_score); client.println("</li>"); client.print("<li>High score: "); client.print(user_settings.high_score); client.println("</li>");
client.print("<li>Boss kills: "); client.print(user_settings.boss_kills); client.println("</li>"); client.print("<li>Boss kills: "); client.print(user_settings.boss_kills); client.println("</li>");
client.print("<button onClick=\"location.href = 'http://192.168.4.1'\">Refresh</button>"); client.print("<button onClick=\"location.href = 'http://192.168.4.1'\">Refresh</button>");
client.print("<h2>Adjustable Settings </h2>"); client.print("<h2>Adjustable Settings </h2>");
client.print("<table>"); client.print("<table>");
client.print("<tr><td>"); client.print("<tr><td>");
client.print("LED Count (60-"); client.print("LED Count (60-");
client.print(MAX_LEDS); client.print(MAX_LEDS);
client.print(")</td><td><form><input type='number' name='C' value='"); client.print(")</td><td><form><input type='number' name='C' value='");
client.print(user_settings.led_count); client.print(user_settings.led_count);
client.print ("' min='60' max='"); client.print ("' min='60' max='");
client.print (MAX_LEDS); client.print (MAX_LEDS);
client.print ("'><input type='submit'></form></td></tr>"); client.print ("'><input type='submit'></form></td></tr>");
client.print("<tr><td>Brightness (10-255)</td><td><form><input type='number' name='B' value='"); client.print("<tr><td>Brightness (10-255)</td><td><form><input type='number' name='B' value='");
client.print(user_settings.led_brightness); client.print(user_settings.led_brightness);
client.print ("' min='10' max='255'><input type='submit'></form></td></tr>"); client.print ("' min='10' max='255'><input type='submit'></form></td></tr>");
client.print("<tr><td>Sound Volume (0-255)</td><td><form><input type='number' name='S' value='"); client.print("<tr><td>Sound Volume (0-255)</td><td><form><input type='number' name='S' value='");
client.print(user_settings.audio_volume); client.print(user_settings.audio_volume);
client.print("' min='0' max='255'><input type='submit'></form></td></tr>"); client.print("' min='0' max='255'><input type='submit'></form></td></tr>");
client.print("<tr><td>Joystick Deadzone (3-12)</td><td><form><input type='number' name='D' value='"); client.print("<tr><td>Joystick Deadzone (3-12)</td><td><form><input type='number' name='D' value='");
client.print(user_settings.joystick_deadzone); client.print(user_settings.joystick_deadzone);
client.print("' min='3' max='12'><input type='submit'></form></td></tr>"); client.print("' min='3' max='12'><input type='submit'></form></td></tr>");
client.print("<tr><td>Attack Sensitivity (20000-35000)</td><td><form><input type='number' name='A' value='"); client.print("<tr><td>Attack Sensitivity (20000-35000)</td><td><form><input type='number' name='A' value='");
client.print(user_settings.attack_threshold); client.print(user_settings.attack_threshold);
client.print("' min='2000' max='35000'><input type='submit'></form></td></tr>"); client.print("' min='2000' max='35000'><input type='submit'></form></td></tr>");
client.print("<tr><td>Lives Per Level (3-9)</td><td><form><input type='number' name='L' value='"); client.print("<tr><td>Lives Per Level (3-9)</td><td><form><input type='number' name='L' value='");
client.print(user_settings.lives_per_level); client.print(user_settings.lives_per_level);
client.print("' min='3' max='9'><input type='submit'></form></td></tr>"); client.print("' min='3' max='9'><input type='submit'></form></td></tr>");
client.print("</table>"); client.print("</table>");
client.println("</body>"); #ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT
client.println("</html>"); client.println("<ul><li><a href=\"/metrics\">Metrics</a></li></ul>");
client.println(); #endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT
client.println("</body>");
client.println("</html>");
client.println();
} }
#ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT
// We need to use print() here since println() prints newlines as CR/LF, which
// Prometheus cannot handle.
#define __prom_metric(metric_name, metric_description, value) \
client.print("# HELP " metric_name " " metric_description "\n"); \
client.print("# TYPE " metric_name " gauge\n"); \
client.print(metric_name " "); \
client.print(value); \
client.print("\n");
static void sendMetricsPage(WiFiClient client)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/plain; charset=utf-8");
client.println("Server: twang_exporter");
client.println();
__prom_metric("twang_games_played", "Number of games played", user_settings.games_played);
__prom_metric("twang_total_points", "Total points", user_settings.total_points);
__prom_metric("twang_high_score", "High score", user_settings.high_score);
__prom_metric("twang_boss_kills", "Boss kills", user_settings.boss_kills);
}
#undef __prom_metric
#endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT
void ap_client_check(){ void ap_client_check(){
int cnt; int cnt;
bool newconn=false; bool newconn=false;
int stat; int stat;
WiFiClient client = server.available(); // listen for incoming clients WiFiClient client = server.available(); // listen for incoming clients
//if (client) { // if you get a client,
// sendStatsPage(client);
// Serial.println("printUploadForm");
//}
bool currentLineIsBlank = true; bool currentLineIsBlank = true;
PAGE_TO_SEND page_to_send = Stats;
while (client.connected()) { while (client.connected()) {
if (client.available()) { if (client.available()) {
char c = client.read(); char c = client.read();
//Serial.write(c); linebuf[charcount]=c;
linebuf[charcount]=c; if (charcount<sizeof(linebuf)-1)
if (charcount<sizeof(linebuf)-1) charcount++;
charcount++;
if (c == '\n' && currentLineIsBlank)
if (c == '\n' && currentLineIsBlank) { {
switch (page_to_send)
{
case Stats:
sendStatsPage(client); sendStatsPage(client);
break; break;
#ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT
case Metrics:
sendMetricsPage(client);
break;
#endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT
} }
if (c == '\n') { break;
// you're starting a new line
currentLineIsBlank = true;
if (strstr(linebuf,"GET /?") > 0)
{
String line = String(linebuf);
int start = line.indexOf('=', 0);
char paramCode = line.charAt(start - 1);
int finish = line.indexOf('H', start+1)-1;
String val = line.substring(start+1, finish);
// if it is not numeric, it will convert to 0.
// The the change_setting function will make sure the range is OK
change_setting(paramCode, val.toInt());
}
// you're starting a new line
currentLineIsBlank = true;
memset(linebuf,0,sizeof(linebuf));
charcount=0;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
} }
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
if (strstr(linebuf,"GET /?") > 0)
{
String line = String(linebuf);
int start = line.indexOf('=', 0);
char paramCode = line.charAt(start - 1);
int finish = line.indexOf('H', start+1)-1;
String val = line.substring(start+1, finish);
// if it is not numeric, it will convert to 0.
// The the change_setting function will make sure the range is OK
change_setting(paramCode, val.toInt());
page_to_send = Stats;
}
#ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT
else if (strstr(linebuf, "GET /metrics"))
{
page_to_send = Metrics;
}
#endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT
// you're starting a new line
currentLineIsBlank = true;
memset(linebuf,0,sizeof(linebuf));
charcount=0;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
} }
} }