From e619f51c8778847c3acb3ad01f5b8b60d44c2caa Mon Sep 17 00:00:00 2001 From: David McGrew Date: Wed, 12 May 2021 13:59:04 -0400 Subject: [PATCH] adding file name rotation to stats output --- src/Makefile.in | 1 + src/control.h | 21 ++++++++++++++----- src/mercury.c | 2 +- src/rotator.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 src/rotator.h diff --git a/src/Makefile.in b/src/Makefile.in index 8cec8475..ca31b97a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -91,6 +91,7 @@ MERC_H += pkt_processing.h MERC_H += pcap_file_io.h MERC_H += pcap_reader.h MERC_H += rnd_pkt_drop.h +MERC_H += rotator.h MERC_H += signal_handling.h MERC_OBJ = $(MERCC:%.cc=%.o) $(MERC:%.c=%.o) diff --git a/src/control.h b/src/control.h index d48b8ecf..eb872d25 100644 --- a/src/control.h +++ b/src/control.h @@ -9,6 +9,7 @@ #include #include #include +#include "rotator.h" #include "libmerc/libmerc.h" class controller { @@ -18,11 +19,12 @@ class controller { const char *stats_filename, size_t num_secs) : mc{merc_ctx}, - stats_file{stats_filename}, + stats_file{stats_filename, ".json.gz"}, num_secs_between_writes{num_secs}, count{num_secs}, controller_thread{}, - shutdown_requested{false} + shutdown_requested{false}, + has_run_at_least_once{false} { if (mc == nullptr) { throw "error: null mercury context passed to control thread"; @@ -35,19 +37,22 @@ class controller { } private: + mercury_context mc; - std::string stats_file; + rotator stats_file; size_t num_secs_between_writes; size_t count; std::thread controller_thread; std::atomic shutdown_requested; + bool has_run_at_least_once; void run_tasks() { while (shutdown_requested.load() == false) { if (count == 0) { count = num_secs_between_writes; - if (mercury_write_stats_data(mc, stats_file.c_str()) == false) { - fprintf(stderr, "error: could not write stats file %s\n", stats_file.c_str()); + const char *fname = stats_file.get_next_name(); + if (mercury_write_stats_data(mc, fname) == false) { + fprintf(stderr, "error: could not write stats file %s\n", fname); } } --count; @@ -64,6 +69,12 @@ class controller { if(controller_thread.joinable()) { controller_thread.join(); } + if (!has_run_at_least_once) { + const char *fname = stats_file.get_current_name(); + if (mercury_write_stats_data(mc, fname) == false) { + fprintf(stderr, "error: could not write stats file %s\n", fname); + } + } } }; diff --git a/src/mercury.c b/src/mercury.c index 8dc37519..f301aa2f 100644 --- a/src/mercury.c +++ b/src/mercury.c @@ -541,7 +541,7 @@ int main(int argc, char *argv[]) { controller *ctl = nullptr; if (cfg.stats_filename) { - ctl = new controller{mc, "mercury-stats.json.gz", 2}; + ctl = new controller{mc, cfg.stats_filename, 30}; } pthread_t output_thread; diff --git a/src/rotator.h b/src/rotator.h new file mode 100644 index 00000000..be55ea72 --- /dev/null +++ b/src/rotator.h @@ -0,0 +1,56 @@ +// rotator.h +// +// file name rotation + +#ifndef ROTATOR_H +#define ROTATOR_H + +#include + +class rotator { +public: + + rotator(const char *filename, + const char *filename_extension=nullptr) : + file_number{0}, + base_name{filename}, + extension{filename_extension}, + file_name{filename} + { + file_name.append(extension); + } + + const char *get_next_name() { + /* + * create filename that includes sequence number and date/timestamp + */ + file_name = base_name; + + char file_num[MAX_HEX]; + snprintf(file_num, MAX_HEX, "%x", file_number++); + file_name.append("-").append(file_num); + + char time_str[128]; + struct timeval now; + gettimeofday(&now, NULL); + strftime(time_str, sizeof(time_str) - 1, "%Y-%m-%d-%H-%M-%S", localtime(&now.tv_sec)); + file_name.append("-").append(time_str); + + file_name.append(extension); + + return file_name.c_str(); + } + + const char *get_current_name() const { + return file_name.c_str(); + } + +private: + unsigned int file_number; + std::string base_name; // prefix common to all files + std::string extension; // extension, if any + std::string file_name; // name of current file + +}; + +#endif // ROTATOR_H