Basic implementation of a JSON logger module
This commit is contained in:
parent
033c26bcae
commit
251aca7738
11
impl/src/debug_structs.h
Normal file
11
impl/src/debug_structs.h
Normal file
|
@ -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
|
114
impl/src/jsonlogger.c
Normal file
114
impl/src/jsonlogger.c
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
30
impl/src/jsonlogger.h
Normal file
30
impl/src/jsonlogger.h
Normal file
|
@ -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 <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -14,6 +14,9 @@
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "jsonlogger.h"
|
||||||
|
#include "debug_structs.h"
|
||||||
|
|
||||||
#include "layer1/tx.h"
|
#include "layer1/tx.h"
|
||||||
#include "layer1/rx.h"
|
#include "layer1/rx.h"
|
||||||
|
|
||||||
|
@ -36,13 +39,7 @@ static bool m_running = true;
|
||||||
|
|
||||||
static double next_tx_switch_time = 0.0;
|
static double next_tx_switch_time = 0.0;
|
||||||
|
|
||||||
static struct {
|
static rx_stats_t m_rx_stats;
|
||||||
size_t preambles_found;
|
|
||||||
size_t successful_decodes;
|
|
||||||
size_t failed_decodes;
|
|
||||||
size_t header_errors;
|
|
||||||
} m_stats;
|
|
||||||
|
|
||||||
|
|
||||||
static void signal_handler(int signal, siginfo_t *info, void *ctx)
|
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");
|
//fprintf(stderr, "=== FAILED PAYLOAD ===\n");
|
||||||
//hexdump(packet_data, packet_len);
|
//hexdump(packet_data, packet_len);
|
||||||
//fprintf(stderr, "=======================\n");
|
//fprintf(stderr, "=======================\n");
|
||||||
m_stats.failed_decodes++;
|
m_rx_stats.failed_decodes++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RX_EVT_HEADER_ERROR:
|
case RX_EVT_HEADER_ERROR:
|
||||||
m_stats.header_errors++;
|
m_rx_stats.header_errors++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RX_EVT_PACKET_RECEIVED:
|
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);
|
//hexdump(packet_data, packet_len < 64 ? packet_len : 64);
|
||||||
//fprintf(stderr, "====================================\n");
|
//fprintf(stderr, "====================================\n");
|
||||||
|
|
||||||
m_stats.successful_decodes++;
|
m_rx_stats.successful_decodes++;
|
||||||
|
|
||||||
block_tx_for(TX_SWITCH_BACKOFF_END_OF_PACKET_MS);
|
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:
|
case RX_EVT_PREAMBLE_FOUND:
|
||||||
//fprintf(stderr, "Found preamble!\n");
|
//fprintf(stderr, "Found preamble!\n");
|
||||||
block_tx_for(TX_SWITCH_BACKOFF_PREAMBLE_MS);
|
block_tx_for(TX_SWITCH_BACKOFF_PREAMBLE_MS);
|
||||||
m_stats.preambles_found++;
|
m_rx_stats.preambles_found++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsonlogger_log_rx_stats(&m_rx_stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,6 +182,11 @@ int main(int argc, char **argv)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!jsonlogger_init("jsonlog.fifo")) {
|
||||||
|
fprintf(stderr, "Could not initialize JSON logger.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
bool on_air = true;
|
bool on_air = true;
|
||||||
|
|
||||||
debug_fd = open("/tmp/dump.cf32", O_CREAT | O_WRONLY | O_TRUNC);
|
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);
|
double rate = total_samples / (new - old);
|
||||||
fprintf(stderr, "\nEstimated rate: %.3f MS/s\n", rate / 1e6);
|
fprintf(stderr, "\nEstimated rate: %.3f MS/s\n", rate / 1e6);
|
||||||
fprintf(stderr, "Receiver statistics:\n");
|
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",
|
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",
|
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",
|
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;
|
next_stats_print_time += 0.5;
|
||||||
|
|
||||||
total_samples = 0;
|
total_samples = 0;
|
||||||
|
@ -386,5 +390,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
sdr_destroy(&sdr);
|
sdr_destroy(&sdr);
|
||||||
|
|
||||||
|
jsonlogger_shutdown();
|
||||||
|
|
||||||
fprintf(stderr, "Done.\n");
|
fprintf(stderr, "Done.\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue