From aff64937000fbce5c55b49bee98f0120e09e399e Mon Sep 17 00:00:00 2001 From: Joseph Hunkeler Date: Sun, 10 May 2026 15:16:48 -0400 Subject: Implement logging facility WARN, INFO, DEBUG * The original macros have been updated * Default log level is WARN * Log level increases per `-v` CLI argument * Tests always use DEBUG level --- src/cli/stasis/stasis_main.c | 1 + src/lib/core/CMakeLists.txt | 1 + src/lib/core/include/core_message.h | 22 +++++---- src/lib/core/include/log.h | 29 +++++++++++ src/lib/core/log.c | 96 +++++++++++++++++++++++++++++++++++++ src/lib/delivery/delivery_test.c | 2 - tests/include/testing.h | 1 + 7 files changed, 140 insertions(+), 12 deletions(-) create mode 100644 src/lib/core/include/log.h create mode 100644 src/lib/core/log.c diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index 95cb7c5..2bc2d4b 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -652,6 +652,7 @@ int main(int argc, char *argv[]) { break; case 'v': globals.verbose = true; + LOG_LEVEL++; break; case OPT_OVERWRITE: globals.enable_overwrite = true; diff --git a/src/lib/core/CMakeLists.txt b/src/lib/core/CMakeLists.txt index 462d7d8..3a54d94 100644 --- a/src/lib/core/CMakeLists.txt +++ b/src/lib/core/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(stasis_core STATIC globals.c + log.c timespec.c str.c strlist.c diff --git a/src/lib/core/include/core_message.h b/src/lib/core/include/core_message.h index aab7203..6ac9cb4 100644 --- a/src/lib/core/include/core_message.h +++ b/src/lib/core/include/core_message.h @@ -2,18 +2,20 @@ #ifndef STASIS_CORE_MESSAGE_H #define STASIS_CORE_MESSAGE_H -#define SYSERROR(MSG, ...) do { \ - fprintf(stderr, STASIS_COLOR_RED "ERROR: " STASIS_COLOR_RESET STASIS_COLOR_WHITE "%s:%d:%s()" STASIS_COLOR_RESET ":%s - ", path_basename(__FILE__), __LINE__, __FUNCTION__, (errno > 0) ? strerror(errno) : "info"); \ - fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \ +#define SYSERROR(FMT, ...) do { \ + log_print_error(EXECPOINT, (FMT), ##__VA_ARGS__); \ } while (0) -#ifdef DEBUG -#define SYSDEBUG(MSG, ...) do { \ - fprintf(stderr, STASIS_COLOR_BLUE "DEBUG: " STASIS_COLOR_RESET STASIS_COLOR_WHITE "%s:%d:%s()" STASIS_COLOR_RESET ": ", path_basename(__FILE__), __LINE__, __FUNCTION__); \ - fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \ +#define SYSWARN(FMT, ...) do { \ + log_print_warning(EXECPOINT, (FMT), ##__VA_ARGS__); \ +} while (0) + +#define SYSINFO(FMT, ...) do { \ + log_print_info(EXECPOINT, (FMT), ##__VA_ARGS__); \ +} while (0) + +#define SYSDEBUG(FMT, ...) do { \ + log_print_debug(EXECPOINT, (FMT), ##__VA_ARGS__); \ } while (0) -#else -#define SYSDEBUG(MSG, ...) do {} while (0) -#endif #endif //STASIS_CORE_MESSAGE_H diff --git a/src/lib/core/include/log.h b/src/lib/core/include/log.h new file mode 100644 index 0000000..18617c4 --- /dev/null +++ b/src/lib/core/include/log.h @@ -0,0 +1,29 @@ +#ifndef STASIS_EXECPOINT_H +#define STASIS_EXECPOINT_H + +#include + +enum LogLevel { + LOG_LEVEL_WARN = 0, + LOG_LEVEL_INFO, + LOG_LEVEL_DEBUG, +}; +extern enum LogLevel LOG_LEVEL; + +struct ExecPoint { + const int line; // line number + const char *file; // file name of origin + const char *function; // function of origin +}; + +#define EXECPOINT (struct ExecPoint) {.line = __LINE__, .file = __FILE__, .function = __FUNCTION__} + +void log_print_error(struct ExecPoint ep, const char *fmt, ...); +void log_print_warning(struct ExecPoint ep, const char *fmt, ...); +void log_print_info(struct ExecPoint ep, const char *fmt, ...); +void log_print_debug(struct ExecPoint ep, const char *fmt, ...); +int log_msgv(FILE *stream, struct ExecPoint ep, const char *preface_color, const char *preface, const char *fmt, va_list ap); +int log_msg(FILE *stream, struct ExecPoint ep, const char *preface_color, const char *preface, const char *fmt, ...); +const char *log_get_level_str(void); + +#endif // STASIS_EXECPOINT_H diff --git a/src/lib/core/log.c b/src/lib/core/log.c new file mode 100644 index 0000000..aea3231 --- /dev/null +++ b/src/lib/core/log.c @@ -0,0 +1,96 @@ +#include "core.h" +#include "log.h" + +enum LogLevel LOG_LEVEL = LOG_LEVEL_WARN; + +void log_print_error(const struct ExecPoint ep, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + log_msgv(stderr, ep, STASIS_COLOR_RED, "ERROR", fmt, ap); + va_end(ap); +} + +void log_print_warning(const struct ExecPoint ep, const char *fmt, ...) { + if (LOG_LEVEL < LOG_LEVEL_WARN) { + return; + } + va_list ap; + va_start(ap, fmt); + log_msgv(stderr, ep, STASIS_COLOR_YELLOW, "WARNING", fmt, ap); + va_end(ap); +} + +void log_print_info(const struct ExecPoint ep, const char *fmt, ...) { + if (LOG_LEVEL < LOG_LEVEL_INFO) { + return; + } + va_list ap; + va_start(ap, fmt); + log_msgv(stdout, ep, STASIS_COLOR_WHITE, "INFO", fmt, ap); + va_end(ap); +} + +void log_print_debug(const struct ExecPoint ep, const char *fmt, ...) { + if (LOG_LEVEL < LOG_LEVEL_DEBUG) { + return; + } + va_list ap; + va_start(ap, fmt); + log_msgv(stderr, ep, STASIS_COLOR_BLUE, "DEBUG", fmt, ap); + va_end(ap); +} + +int log_msgv(FILE *stream, const struct ExecPoint ep, const char *preface_color, const char *preface, const char *fmt, va_list ap) { + char header[STASIS_BUFSIZ] = {0}; + + int len = snprintf(header, sizeof(header), + STASIS_COLOR_RESET + "%s%s: " + STASIS_COLOR_RESET + STASIS_COLOR_WHITE + "%s:%d: %s(): " + STASIS_COLOR_RESET, + preface_color ? preface_color : STASIS_COLOR_RED, + preface ? preface : "UNKNOWN", + path_basename((char *) ep.file), + ep.line, + ep.function); + if (len >= (int) sizeof(header)) { + SYSERROR("header format truncated (%d >= %d)", len, (int) sizeof(header)); + return len; + } + + fprintf(stream, "%s", header); + + va_list ap_out; + va_copy(ap_out, ap); + len = vfprintf(stream, fmt ? fmt : "NO MESSAGE", ap_out); + va_end(ap_out); + if (len < 0) { + SYSERROR("\nvfprintf failed"); + return len; + } + fprintf(stderr, LINE_SEP); + return len; +} + +int log_msg(FILE *stream, const struct ExecPoint ep, const char *preface_color, const char *preface, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + const int ret = log_msgv(stream, ep, preface_color, preface, fmt, ap); + va_end(ap); + return ret; +} + +const char *log_get_level_str(void) { + switch (LOG_LEVEL) { + case LOG_LEVEL_WARN: + return "WARN"; + case LOG_LEVEL_INFO: + return "INFO"; + case LOG_LEVEL_DEBUG: + default: + // Anything higher is still DEBUG + return "DEBUG"; + } +} diff --git a/src/lib/delivery/delivery_test.c b/src/lib/delivery/delivery_test.c index 5d5a3e8..119fe95 100644 --- a/src/lib/delivery/delivery_test.c +++ b/src/lib/delivery/delivery_test.c @@ -18,9 +18,7 @@ struct Tests *tests_init(const size_t num_tests) { int tests_add(struct Tests *tests, struct Test *x) { if (tests->num_used >= tests->num_alloc) { -#ifdef DEBUG const size_t old_alloc = tests->num_alloc; -#endif struct Test **tmp = realloc(tests->test, tests->num_alloc++ * sizeof(**tests->test)); SYSDEBUG("Increasing size of test array: %zu -> %zu", old_alloc, tests->num_alloc); if (!tmp) { diff --git a/tests/include/testing.h b/tests/include/testing.h index e446908..728b6a6 100644 --- a/tests/include/testing.h +++ b/tests/include/testing.h @@ -214,6 +214,7 @@ inline void stasis_testing_teardown_workspace() { SYSERROR("%s", "Unable to determine current working directory"); \ exit(1); \ } \ + LOG_LEVEL = LOG_LEVEL_DEBUG; \ atexit(stasis_testing_record_result_summary); \ atexit(stasis_testing_teardown_workspace); \ stasis_testing_setup_workspace(); \ -- cgit