From 0dbbe819c7c160cd9c13fe470df6faa7cab34646 Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" <zany@triq.net> Date: Sat, 16 Mar 2024 12:14:00 +0100 Subject: [PATCH] Add OpenMetrics/Prometheus API (#2863) --- include/rtl_433.h | 19 +++++++++---- src/http_server.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ src/r_api.c | 5 ++-- src/rtl_433.c | 16 ++++++++--- 4 files changed, 101 insertions(+), 11 deletions(-) diff --git a/include/rtl_433.h b/include/rtl_433.h index 1d9eb66b..136ceb5b 100644 --- a/include/rtl_433.h +++ b/include/rtl_433.h @@ -116,11 +116,20 @@ typedef struct r_cfg { char const *sr_filename; int sr_execopen; int watchdog; ///< SDR acquire stall watchdog - /* stats*/ - time_t frames_since; ///< stats start time - unsigned frames_count; ///< stats counter for interval - unsigned frames_fsk; ///< stats counter for interval - unsigned frames_events; ///< stats counter for interval + /* global stats */ + time_t running_since; ///< program start time statistic + unsigned total_frames_count; ///< total frames recieved statistic + unsigned total_frames_squelch; ///< total frames with noise only statistic + unsigned total_frames_ook; ///< total frames with ook demod statistic + unsigned total_frames_fsk; ///< total frames with fsk demod statistic + unsigned total_frames_events; ///< total frames with decoder events statistic + /* sdr stats */ + time_t sdr_since; ///< time of last SDR connect statistic + /* per report interval stats */ + time_t frames_since; ///< time at start of report interval statistic + unsigned frames_ook; ///< counter of ook demods for report interval statistic + unsigned frames_fsk; ///< counter of fsk demods for report interval statistic + unsigned frames_events; ///< counter of decoder events for report interval statistic struct mg_mgr *mgr; } r_cfg_t; diff --git a/src/http_server.c b/src/http_server.c index 0911551e..2de06b1f 100644 --- a/src/http_server.c +++ b/src/http_server.c @@ -733,6 +733,75 @@ static void handle_redirect(struct mg_connection *nc, struct http_message *hm) "\r\n\r\n"); } +static void handle_openmetrics(struct mg_connection *nc, struct http_message *hm) +{ + if (mg_vcmp(&hm->method, "GET") != 0) { + mg_http_send_error(nc, 405, NULL); // 405 Method Not Allowed + return; + } + + struct http_server_context *ctx = nc->user_data; + r_cfg_t *cfg = ctx->cfg; + + time_t now; + time(&now); + + char buf[2000]; + int len = snprintf(buf, sizeof(buf), + "# TYPE uptime_seconds counter\n" + "# UNIT uptime_seconds seconds\n" + "# HELP uptime_seconds Program uptime.\n" + "uptime_seconds_total %.1f\n" + "uptime_seconds_created %.1f\n" + "# TYPE decoder_enabled gauge\n" + "# HELP decoder_enabled Number of enabled decoders.\n" + "decoder_enabled %u\n" + "# TYPE input_uptime_seconds counter\n" + "# UNIT input_uptime_seconds seconds\n" + "# HELP input_uptime_seconds SDR Receiver uptime.\n" + "input_uptime_seconds_total %.1f\n" + "input_uptime_seconds_created %.1f\n" + "# TYPE input_count_frames counter\n" + "# UNIT input_count_frames frames\n" + "# HELP input_count_frames Number of SDR frames received.\n" + "input_count_frames_total %u\n" + "# TYPE input_squelch_frames counter\n" + "# UNIT input_squelch_frames frames\n" + "# HELP input_squelch_frames Number of SDR frames skipped by squelch.\n" + "input_squelch_frames_total %u\n" + "# TYPE input_ook_frames counter\n" + "# UNIT input_ook_frames frames\n" + "# HELP input_ook_frames Number of SDR frames with OOK demodulation.\n" + "input_ook_frames_total %u\n" + "# TYPE input_fsk_frames counter\n" + "# UNIT input_fsk_frames frames\n" + "# HELP input_fsk_frames Number of SDR frames with FSK demodulation.\n" + "input_fsk_frames_total %u\n" + "# TYPE input_event_frames counter\n" + "# UNIT input_event_frames frames\n" + "# HELP input_event_frames Number of SDR frames with decode events.\n" + "input_event_frames_total %u\n" + "# EOF\n", + (float)(now - cfg->running_since), // uptime_seconds_total, + (float)cfg->running_since, // uptime_seconds_created, + (unsigned)cfg->demod->r_devs.len, // decoder_enabled, + (float)(now - cfg->sdr_since), // input_uptime_seconds_total, + (float)cfg->sdr_since, // input_uptime_seconds_created, + cfg->total_frames_count, // input_count_frames_total, + cfg->total_frames_squelch, // input_squelch_frames_total, + cfg->total_frames_ook, // input_ook_frames_total, + cfg->total_frames_fsk, // input_fsk_frames_total, + cfg->total_frames_events); // input_event_frames_total, + + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Length: %u\r\n" + "\r\n", + len); + mg_send(nc, buf, (size_t)len); + nc->flags |= MG_F_SEND_AND_CLOSE; +} + // reply to ws command static void rpc_response_ws(rpc_t *rpc, int ret_code, char const *message, int arg) { @@ -1039,6 +1108,9 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) else if (mg_vcmp(&hm->uri, "/stream") == 0) { handle_json_stream(nc, hm); } + else if (mg_vcmp(&hm->uri, "/metrics") == 0) { + handle_openmetrics(nc, hm); + } else if (mg_vcmp(&hm->uri, "/api") == 0) { //handle_api_query(nc, hm); } diff --git a/src/r_api.c b/src/r_api.c index 01a5ac2f..6ad85ece 100644 --- a/src/r_api.c +++ b/src/r_api.c @@ -187,6 +187,7 @@ void r_init_cfg(r_cfg_t *cfg) // initialize tables baseband_init(); + time(&cfg->running_since); time(&cfg->frames_since); get_time_now(&cfg->demod->now); @@ -938,7 +939,7 @@ data_t *create_report_data(r_cfg_t *cfg, int level) } data = data_make( - "count", "", DATA_INT, cfg->frames_count, + "count", "", DATA_INT, cfg->frames_ook, "fsk", "", DATA_INT, cfg->frames_fsk, "events", "", DATA_INT, cfg->frames_events, NULL); @@ -962,7 +963,7 @@ void flush_report_data(r_cfg_t *cfg) list_t *r_devs = &cfg->demod->r_devs; time(&cfg->frames_since); - cfg->frames_count = 0; + cfg->frames_ook = 0; cfg->frames_fsk = 0; cfg->frames_events = 0; diff --git a/src/rtl_433.c b/src/rtl_433.c index 2bb3f6f4..8f11ca79 100644 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -460,7 +460,9 @@ static void sdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) int noise_only = avg_db < demod->noise_level + 3.0f; // or demod->min_level_auto? // always process frames if loader, dumper, or analyzers are in use, otherwise skip silent frames int process_frame = demod->squelch_offset <= 0 || !noise_only || demod->load_info.format || demod->analyze_pulses || demod->dumper.len || demod->samp_grab; + cfg->total_frames_count += 1; if (noise_only) { + cfg->total_frames_squelch += 1; demod->noise_level = (demod->noise_level * 7 + avg_db) / 8; // fast fall over 8 frames // If auto_level and noise level well below min_level and significant change in noise level if (demod->auto_level > 0 && demod->noise_level < demod->min_level - 3.0f @@ -479,8 +481,9 @@ static void sdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) noise_only ? "noise" : "signal", avg_db, demod->noise_level); } - if (process_frame) - baseband_low_pass_filter(demod->buf.temp, demod->am_buf, n_samples, &demod->lowpass_filter_state); + if (process_frame) { + baseband_low_pass_filter(demod->buf.temp, demod->am_buf, n_samples, &demod->lowpass_filter_state); + } // FM demodulation // Select the correct fsk pulse detector @@ -539,7 +542,9 @@ static void sdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) if (demod->analyze_pulses) fprintf(stderr, "Detected OOK package\t%s\n", time_pos_str(cfg, demod->pulse_data.start_ago, time_str)); p_events += run_ook_demods(&demod->r_devs, &demod->pulse_data); - cfg->frames_count++; + cfg->total_frames_ook += 1; + cfg->total_frames_events += p_events > 0; + cfg->frames_ook +=1; cfg->frames_events += p_events > 0; for (void **iter = demod->dumper.elems; iter && *iter; ++iter) { @@ -564,7 +569,9 @@ static void sdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) if (demod->analyze_pulses) fprintf(stderr, "Detected FSK package\t%s\n", time_pos_str(cfg, demod->fsk_pulse_data.start_ago, time_str)); p_events += run_fsk_demods(&demod->r_devs, &demod->fsk_pulse_data); - cfg->frames_fsk++; + cfg->total_frames_fsk +=1; + cfg->total_frames_events += p_events > 0; + cfg->frames_fsk += 1; cfg->frames_events += p_events > 0; for (void **iter = demod->dumper.elems; iter && *iter; ++iter) { @@ -1517,6 +1524,7 @@ static void timer_handler(struct mg_connection *nc, int ev, void *ev_data) if (cfg->dev_state == DEVICE_STATE_STARTING || cfg->dev_state == DEVICE_STATE_GRACE) { cfg->dev_state = DEVICE_STATE_STARTED; + time(&cfg->sdr_since); } cfg->watchdog = 0; break;