#include "log.h" static struct { char *name; int set; FILE *fps[MAX_LOGFILES]; int nfps; int stder; #ifdef COLOR char *color; #endif } log_levels[LOG_LEVEL_COUNT] = { { .name = "DEBUG", .set = 1, .fps = {0}, .nfps = 0, .stder = 1, #ifdef COLOR .color = "\e[38;2;255;255;0m" #endif }, { .name = "INFO", .set = 1, .fps = {0}, .nfps = 0, .stder = 1, #ifdef COLOR .color = "\e[38;2;0;224;255m" #endif }, { .name = "WARN", .set = 1, .fps = {0}, .nfps = 0, .stder = 1, #ifdef COLOR .color = "\e[38;2;255;165;0m" #endif }, { .name = "ERROR", .set = 1, .fps = {0}, .nfps = 0, .stder = 1, #ifdef COLOR .color = "\e[38;2;255;0;0m" #endif } }; static char time_format[16] = "%T"; static int nanosecond_precision = 0; int log_set_stderr(int level, int of){ if(level >= 0 && level < LOG_LEVEL_COUNT){ return log_levels[level].stder = of; } return 0; } void log_set_level(int level, int of){ if(level >= 0 && level < LOG_LEVEL_COUNT){ log_levels[level].set = of; } } int log_add_fp(int level, FILE *fp){ if(level >= 0 && level < LOG_LEVEL_COUNT && log_levels[level].nfps < MAX_LOGFILES-1){ log_levels[level].fps[log_levels[level].nfps++] = fp; return 0; } return 1; } void log_time_format(char *tf){ strncpy(time_format, tf, sizeof(time_format)/sizeof(time_format[0])); } int log_nanoseconds(int n){ return nanosecond_precision = n%10; } void log_message(int level, char *file, int line, char *fmt, ...){ struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); if(level >= 0 && level < LOG_LEVEL_COUNT && log_levels[level].set){ struct tm *lt = localtime(&ts.tv_sec); char t[32] = {0}; strftime(t, 31, time_format, lt); char ns[9] = {0}; snprintf(ns, nanosecond_precision+1, "%ld", ts.tv_nsec); char msg[MSG_LIMIT] = {0}; int written = snprintf(msg, MSG_LIMIT-2, #ifdef PID "[%d] " #endif "%s%s%s%s%s%s%s\t", #ifdef PID getpid(), #endif t, nanosecond_precision ? "." : "", ns, t[0] != '\0' ? " " : "", #ifdef COLOR log_levels[level].color, #else "", #endif log_levels[level].name, "\e[0m" ); if(level == LOG_DEBUG){ written += snprintf(msg+written, MSG_LIMIT-2-written, "%s:%d: ",file, line); } va_list args; va_start(args, fmt); written += vsnprintf(msg+written, MSG_LIMIT-2-written, fmt, args); msg[written] = '\n'; if(log_levels[level].stder) fputs(msg, stderr); for(int i = 0; i < log_levels[level].nfps; i++){ if(log_levels[level].fps[i] != NULL) fputs(msg, log_levels[level].fps[i++]); } } }