diff --git a/src/log.c b/src/log.c index 2e183b0..f9e43f6 100644 --- a/src/log.c +++ b/src/log.c @@ -25,112 +25,161 @@ #include #include #include - #include "log.h" - -static struct { - void *udata; - log_LockFn lock; - FILE *fp; - int level; - int quiet; +#include + +static struct +{ + void *udata; + log_LockFn lock; + FILE *fp; + int console_level; + int file_level; + int quiet; } L; +static void time_to_str(char *); + +static int year; +static int month; +static int day; +static int hour; +static int minutes; +static int seconds; +static int usec; -static const char *level_names[] = { - "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" -}; +char time_string[25]; + +static struct timeval tv; +static struct tm *tm; #ifdef LOG_USE_COLOR static const char *level_colors[] = { - "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" -}; + "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"}; #endif - -static void lock(void) { - if (L.lock) { - L.lock(L.udata, 1); - } +const char *getLevelName(int level) +{ + if (level >= MIN_LOG_LEVEL && level <= MAX_LOG_LEVEL) + return level_names[level]; + else + return "INVALID LOG LEVEL"; } - -static void unlock(void) { - if (L.lock) { - L.lock(L.udata, 0); - } +static void lock(void) +{ + if (L.lock) + { + L.lock(L.udata, 1); + } } - -void log_set_udata(void *udata) { - L.udata = udata; +static void unlock(void) +{ + if (L.lock) + { + L.lock(L.udata, 0); + } } - -void log_set_lock(log_LockFn fn) { - L.lock = fn; +void log_set_udata(void *udata) +{ + L.udata = udata; } - -void log_set_fp(FILE *fp) { - L.fp = fp; +void log_set_lock(log_LockFn fn) +{ + L.lock = fn; } - -void log_set_level(int level) { - L.level = level; +void log_set_fp(FILE *fp) +{ + L.fp = fp; } - -void log_set_quiet(int enable) { - L.quiet = enable ? 1 : 0; +void log_set_console_level(int level) +{ + L.console_level = level; } +void log_set_file_level(int level) +{ + L.file_level = level; +} -void log_log(int level, const char *file, int line, const char *fmt, ...) { - if (level < L.level) { - return; - } - - /* Acquire lock */ - lock(); +void log_set_quiet(int enable) +{ + L.quiet = enable ? 1 : 0; +} - /* Get current time */ - time_t t = time(NULL); - struct tm *lt = localtime(&t); +void log_log(int level, const char *file, int line, const char *fmt, ...) +{ + if (level < L.console_level && level < L.file_level) + { + return; + } + + /* Acquire lock */ + lock(); + time_to_str(time_string); + /* Log to stderr */ + if (!L.quiet && level >= L.console_level) + { + va_list args; + + #ifdef LOG_USE_COLOR + fprintf( + stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", + time_string, level_colors[level], level_names[level], file, line); + #else + fprintf(stderr, "%s %-5s %s:%d: ", time_string, level_names[level], file, line); + #endif + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); + } + + /* Log to file */ + if (L.fp && level >= L.file_level) + { + va_list args; + fprintf(L.fp, "%s %-5s %s:%d: ", time_string, level_names[level], file, line); + va_start(args, fmt); + vfprintf(L.fp, fmt, args); + va_end(args); + fprintf(L.fp, "\n"); + fflush(L.fp); + } + + /* Release lock */ + unlock(); +} - /* 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); - } - - /* 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); - } - - /* Release lock */ - unlock(); +/* Write time to buf in format YYYY-MM-DD HH:MM:SS.ms */ +static void time_to_str(char *buf) +{ + gettimeofday(&tv, NULL); + tm = localtime(&tv.tv_sec); + /* Add 1900 to get the right year value read the manual page for localtime() */ + year = tm->tm_year + 1900; + /* Months are 0 indexed in struct tm */ + month = tm->tm_mon + 1; + day = tm->tm_mday; + hour = tm->tm_hour; + minutes = tm->tm_min; + seconds = tm->tm_sec; + usec = tv.tv_usec; + // msec + // buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0'; + int len = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d ", + year, + month, + day, + hour, + minutes, + seconds, + usec); + buf[len] = '\0'; } diff --git a/src/log.h b/src/log.h index b3df494..5f9605f 100644 --- a/src/log.h +++ b/src/log.h @@ -11,6 +11,12 @@ #include #include +#define MIN_LOG_LEVEL 0 // TRACE +#define MAX_LOG_LEVEL 5 // FATAL +static const char *level_names[] = { + "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" +}; + #define LOG_VERSION "0.1.0" typedef void (*log_LockFn)(void *udata, int lock); @@ -27,9 +33,12 @@ enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; void log_set_udata(void *udata); void log_set_lock(log_LockFn fn); void log_set_fp(FILE *fp); -void log_set_level(int level); +void log_set_console_level(int level); +void log_set_file_level(int level); void log_set_quiet(int enable); void log_log(int level, const char *file, int line, const char *fmt, ...); +const char* getLevelName(int level); + #endif