From 4c5da2155e0d60c704848fe5312d6049ddf04c08 Mon Sep 17 00:00:00 2001 From: rxi Date: Sat, 20 Jun 2020 08:36:28 +0100 Subject: [PATCH] Updated to use callback based system --- src/log.c | 156 ++++++++++++++++++++++++++++++++---------------------- src/log.h | 24 +++++++-- 2 files changed, 113 insertions(+), 67 deletions(-) diff --git a/src/log.c b/src/log.c index 2e183b0..23516c9 100644 --- a/src/log.c +++ b/src/log.c @@ -20,24 +20,26 @@ * IN THE SOFTWARE. */ -#include -#include -#include -#include -#include - #include "log.h" +#define MAX_CALLBACKS 32 + +typedef struct { + log_LogFn fn; + void *udata; + int level; +} Callback; + static struct { void *udata; log_LockFn lock; - FILE *fp; int level; - int quiet; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; } L; -static const char *level_names[] = { +static const char *level_strings[] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }; @@ -48,32 +50,55 @@ static const char *level_colors[] = { #endif +static void stdout_callback(log_Event *ev) { + char buf[16]; + buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf( + ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + buf, level_colors[ev->level], level_strings[ev->level], + ev->file, ev->line); +#else + fprintf( + ev->udata, "%s %-5s %s:%d: ", + buf, level_strings[ev->level], ev->file, ev->line); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + + +static void file_callback(log_Event *ev) { + char buf[64]; + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf( + ev->udata, "%s %-5s %s:%d: ", + buf, level_strings[ev->level], ev->file, ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + + static void lock(void) { - if (L.lock) { - L.lock(L.udata, 1); - } + if (L.lock) { L.lock(true, L.udata); } } static void unlock(void) { - if (L.lock) { - L.lock(L.udata, 0); - } + if (L.lock) { L.lock(false, L.udata); } } -void log_set_udata(void *udata) { - L.udata = udata; +const char* log_level_string(int level) { + return level_strings[level]; } -void log_set_lock(log_LockFn fn) { +void log_set_lock(log_LockFn fn, void *udata) { L.lock = fn; -} - - -void log_set_fp(FILE *fp) { - L.fp = fp; + L.udata = udata; } @@ -82,55 +107,62 @@ void log_set_level(int level) { } -void log_set_quiet(int enable) { - L.quiet = enable ? 1 : 0; +void log_set_quiet(bool enable) { + L.quiet = enable; +} + + +int log_add_callback(log_LogFn fn, void *udata, int level) { + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + + +int log_add_fp(FILE *fp, int level) { + return log_add_callback(file_callback, fp, level); +} + + +static void init_event(log_Event *ev, void *udata) { + if (!ev->time) { + time_t t = time(NULL); + ev->time = localtime(&t); + } + ev->udata = udata; } void log_log(int level, const char *file, int line, const char *fmt, ...) { - if (level < L.level) { - return; - } + log_Event ev = { + .fmt = fmt, + .file = file, + .line = line, + .level = level, + }; - /* Acquire lock */ lock(); - /* Get current time */ - time_t t = time(NULL); - struct tm *lt = localtime(&t); - - /* Log to stderr */ - if (!L.quiet) { - va_list args; - char buf[16]; - buf[strftime(buf, sizeof(buf), "%H:%M:%S", lt)] = '\0'; -#ifdef LOG_USE_COLOR - fprintf( - stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", - buf, level_colors[level], level_names[level], file, line); -#else - fprintf(stderr, "%s %-5s %s:%d: ", buf, level_names[level], file, line); -#endif - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - fflush(stderr); + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); } - /* Log to file */ - if (L.fp) { - va_list args; - char buf[32]; - buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0'; - fprintf(L.fp, "%s %-5s %s:%d: ", buf, level_names[level], file, line); - va_start(args, fmt); - vfprintf(L.fp, fmt, args); - va_end(args); - fprintf(L.fp, "\n"); - fflush(L.fp); + for (int i = 0; L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } } - /* Release lock */ unlock(); } diff --git a/src/log.h b/src/log.h index b3df494..48cd51b 100644 --- a/src/log.h +++ b/src/log.h @@ -10,10 +10,23 @@ #include #include +#include +#include #define LOG_VERSION "0.1.0" -typedef void (*log_LockFn)(void *udata, int lock); +typedef struct { + va_list ap; + const char *fmt; + const char *file; + struct tm *time; + void *udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; @@ -24,11 +37,12 @@ enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) -void log_set_udata(void *udata); -void log_set_lock(log_LockFn fn); -void log_set_fp(FILE *fp); +const char* log_level_string(int level); +void log_set_lock(log_LockFn fn, void *udata); void log_set_level(int level); -void log_set_quiet(int enable); +void log_set_quiet(bool enable); +int log_add_callback(log_LogFn fn, void *udata, int level); +int log_add_fp(FILE *fp, int level); void log_log(int level, const char *file, int line, const char *fmt, ...);