From 251aca7738b03967d266d1768b602dd011046537 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 5 May 2024 18:09:00 +0200 Subject: [PATCH] Basic implementation of a JSON logger module --- impl/src/debug_structs.h | 11 ++++ impl/src/jsonlogger.c | 114 +++++++++++++++++++++++++++++++++++++++ impl/src/jsonlogger.h | 30 +++++++++++ impl/src/main.c | 36 +++++++------ 4 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 impl/src/debug_structs.h create mode 100644 impl/src/jsonlogger.c create mode 100644 impl/src/jsonlogger.h diff --git a/impl/src/debug_structs.h b/impl/src/debug_structs.h new file mode 100644 index 0000000..c1ca239 --- /dev/null +++ b/impl/src/debug_structs.h @@ -0,0 +1,11 @@ +#ifndef DEBUG_STRUCTS_H +#define DEBUG_STRUCTS_H + +typedef struct { + size_t preambles_found; + size_t successful_decodes; + size_t failed_decodes; + size_t header_errors; +} rx_stats_t; + +#endif // DEBUG_STRUCTS_H diff --git a/impl/src/jsonlogger.c b/impl/src/jsonlogger.c new file mode 100644 index 0000000..eef5837 --- /dev/null +++ b/impl/src/jsonlogger.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "jsonlogger.h" + +#define LOG_OR_RETURN(...) \ + if(dprintf(m_fifo_fd, __VA_ARGS__) < 0) { \ + return false; \ + } + +static int m_fifo_fd = -1; + +static bool start_message(void) +{ + ssize_t ret = write(m_fifo_fd, "{", 1); + if(ret < 0) { + // FIFO is not writable or other error + if(errno != EAGAIN) { + perror("write"); + } + + return false; + } + + return true; +} + +static bool end_message(void) +{ + ssize_t ret = write(m_fifo_fd, "}\n", 2); + if(ret < 0) { + // FIFO is not writable or other error + if(errno != EAGAIN) { + perror("write"); + } + + return false; + } + + return true; +} + + +bool jsonlogger_init(const char *fifoname) +{ + // try to create the named FIFO + int ret = mkfifo(fifoname, 0666); + if(ret < 0) { + if(errno != EEXIST) { + perror("mkfifo"); + return false; + } + } + + // FIFO was created or did already exist -> open it + m_fifo_fd = open(fifoname, O_WRONLY | O_NONBLOCK); + if(m_fifo_fd < 0) { + perror("open"); + return false; + } + + return true; +} + + +void jsonlogger_shutdown(void) +{ + close(m_fifo_fd); +} + + +bool jsonlogger_log_simple_integer(const char *msg_type, int64_t value) +{ + if(!start_message()) { + return false; + } + + LOG_OR_RETURN("\"%s\": %ld", msg_type, value); + + return end_message(); +} + + +bool jsonlogger_log_simple_double(const char *msg_type, double value) +{ + if(!start_message()) { + return false; + } + + LOG_OR_RETURN("\"%s\": %g", msg_type, value); + + return end_message(); +} + + +bool jsonlogger_log_rx_stats(const rx_stats_t *rx_stats) +{ + if(!start_message()) { + return false; + } + + LOG_OR_RETURN("\"preambles_found\": %zd, ", rx_stats->preambles_found); + LOG_OR_RETURN("\"successful_decodes\": %zd, ", rx_stats->successful_decodes); + LOG_OR_RETURN("\"failed_decodes\": %zd, ", rx_stats->failed_decodes); + LOG_OR_RETURN("\"header_errors\": %zd, ", rx_stats->header_errors); + + return end_message(); +} diff --git a/impl/src/jsonlogger.h b/impl/src/jsonlogger.h new file mode 100644 index 0000000..ba523e2 --- /dev/null +++ b/impl/src/jsonlogger.h @@ -0,0 +1,30 @@ +#ifndef JSONLOGGER_H +#define JSONLOGGER_H + +/*! + * \file + * + * \brief A structured logger. + * + * \details + * This module provides structured log output (in JSON format) for debugging + * purposes. It opens a named pipe (FIFO) and writes JSON objects to them as + * soon as a program opens the reading end. + * + * Each JSON object is written as a single line. + */ + +#include +#include + +#include "debug_structs.h" + +bool jsonlogger_init(const char *fifoname); +void jsonlogger_shutdown(void); + +bool jsonlogger_log_simple_integer(const char *msg_type, int64_t value); +bool jsonlogger_log_simple_double(const char *msg_type, double value); + +bool jsonlogger_log_rx_stats(const rx_stats_t *rx_stats); + +#endif // JSONLOGGER_H diff --git a/impl/src/main.c b/impl/src/main.c index d2d27ad..f36f605 100644 --- a/impl/src/main.c +++ b/impl/src/main.c @@ -14,6 +14,9 @@ #include "utils.h" #include "options.h" +#include "jsonlogger.h" +#include "debug_structs.h" + #include "layer1/tx.h" #include "layer1/rx.h" @@ -36,13 +39,7 @@ static bool m_running = true; static double next_tx_switch_time = 0.0; -static struct { - size_t preambles_found; - size_t successful_decodes; - size_t failed_decodes; - size_t header_errors; -} m_stats; - +static rx_stats_t m_rx_stats; static void signal_handler(int signal, siginfo_t *info, void *ctx) { @@ -122,11 +119,11 @@ void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len) //fprintf(stderr, "=== FAILED PAYLOAD ===\n"); //hexdump(packet_data, packet_len); //fprintf(stderr, "=======================\n"); - m_stats.failed_decodes++; + m_rx_stats.failed_decodes++; break; case RX_EVT_HEADER_ERROR: - m_stats.header_errors++; + m_rx_stats.header_errors++; break; case RX_EVT_PACKET_RECEIVED: @@ -135,7 +132,7 @@ void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len) //hexdump(packet_data, packet_len < 64 ? packet_len : 64); //fprintf(stderr, "====================================\n"); - m_stats.successful_decodes++; + m_rx_stats.successful_decodes++; block_tx_for(TX_SWITCH_BACKOFF_END_OF_PACKET_MS); @@ -148,9 +145,11 @@ void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len) case RX_EVT_PREAMBLE_FOUND: //fprintf(stderr, "Found preamble!\n"); block_tx_for(TX_SWITCH_BACKOFF_PREAMBLE_MS); - m_stats.preambles_found++; + m_rx_stats.preambles_found++; break; } + + jsonlogger_log_rx_stats(&m_rx_stats); } @@ -183,6 +182,11 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + if(!jsonlogger_init("jsonlog.fifo")) { + fprintf(stderr, "Could not initialize JSON logger.\n"); + return EXIT_FAILURE; + } + bool on_air = true; debug_fd = open("/tmp/dump.cf32", O_CREAT | O_WRONLY | O_TRUNC); @@ -352,13 +356,13 @@ int main(int argc, char **argv) double rate = total_samples / (new - old); fprintf(stderr, "\nEstimated rate: %.3f MS/s\n", rate / 1e6); fprintf(stderr, "Receiver statistics:\n"); - fprintf(stderr, " Preambles found: %8zd\n", m_stats.preambles_found); + fprintf(stderr, " Preambles found: %8zd\n", m_rx_stats.preambles_found); fprintf(stderr, " Successful decodes: %8zd (%6.2f %%)\n", - m_stats.successful_decodes, m_stats.successful_decodes * 100.0f / m_stats.preambles_found); + m_rx_stats.successful_decodes, m_rx_stats.successful_decodes * 100.0f / m_rx_stats.preambles_found); fprintf(stderr, " Header errors: %8zd (%6.2f %%)\n", - m_stats.header_errors, m_stats.header_errors * 100.0f / m_stats.preambles_found); + m_rx_stats.header_errors, m_rx_stats.header_errors * 100.0f / m_rx_stats.preambles_found); fprintf(stderr, " Failed decodes: %8zd (%6.2f %%)\n", - m_stats.failed_decodes, m_stats.failed_decodes * 100.0f / m_stats.preambles_found); + m_rx_stats.failed_decodes, m_rx_stats.failed_decodes * 100.0f / m_rx_stats.preambles_found); next_stats_print_time += 0.5; total_samples = 0; @@ -386,5 +390,7 @@ int main(int argc, char **argv) sdr_destroy(&sdr); + jsonlogger_shutdown(); + fprintf(stderr, "Done.\n"); }