#include "logger.h" #include "logger_module.h" #include "module_system.h" #include #include #include #define BZ_GET_LOGGER_MODULE() ((BzLoggerModule *) bzModuleRetrieve(BZ_MODULE_LOGGER)) bool bzLoggerInit() { if (bzModuleIsAllocated(BZ_MODULE_LOGGER)) return false; BzLoggerModule *logger = bzModuleAllocate(BZ_MODULE_LOGGER, sizeof(*logger)); if (logger == NULL) return false; logger->level = BZ_LOG_INFO; logger->silent = false; setvbuf(stdout, logger->buffer, _IOFBF, sizeof(logger->buffer)); return true; } void bzLoggerDeinit() { BzLoggerModule *logger = BZ_GET_LOGGER_MODULE(); bzModuleFree(BZ_MODULE_LOGGER); } void bzLoggerEnableDefaultLog(bool enable) { BZ_GET_LOGGER_MODULE()->silent = !enable; } void bzLoggerSetLevel(BzLoggerLevel level) { BZ_GET_LOGGER_MODULE()->level = level; } BzLoggerLevel bzLoggerGetLevel() { return BZ_GET_LOGGER_MODULE()->level; } static const char *LEVEL_STRINGS[] = { "TRACE", "DEBUG", "INFO", "WARNING", "ERROR", "FATAL" }; static const char *LEVEL_COLORS[] = { "\x1b[90m", // TRACE -> Bright black "\x1b[96m", // DEBUG -> Bright cyan "\x1b[32m", // INFO -> Green "\x1b[33m", // WARN -> Yellow "\x1b[31m", // ERROR -> Red "\x1b[91m", // FATAL -> Bright red }; static void bzLoggerStdOutCallback(BzLoggerEvent *ev) { fprintf(stdout, "%s %s%-5s\x1b[0m ",ev->time, LEVEL_COLORS[ev->level], LEVEL_STRINGS[ev->level]); if (ev->file) { fprintf(stdout, "\x1b[90m(%s:%d)\x1b[0m ", ev->file, ev->line); } vfprintf(stdout, ev->fmt, ev->va); fprintf(stdout, "\n"); fflush(stdout); } static void bzLoggerFileCallback(BzLoggerEvent *ev) { FILE *fp = ev->userData; fprintf(fp, "%s %-5s ", ev->time, LEVEL_STRINGS[ev->level]); if (ev->file) { fprintf(fp, "(%s:%d): ", ev->file, ev->line); } vfprintf(fp, ev->fmt, ev->va); fflush(fp); } void bzLoggerLog(BzLoggerLevel level, const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); bzLoggerLogV(level, file, line, fmt, args); va_end(args); } void bzLoggerLogV(BzLoggerLevel level, const char *file, int line, const char *fmt, va_list va) { BzLoggerEvent event = {NULL, NULL, level, file, line, fmt}; const int loggerLevel = bzLoggerGetLevel(); time_t t = time(NULL); struct tm *lt = localtime(&t); char timeBuf[16]; size_t lastIdx = strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", lt); // TODO: Assert timeBuf[lastIdx] = '\0'; event.time = timeBuf; if (!BZ_GET_LOGGER_MODULE()->silent && level >= loggerLevel) { event.userData = stderr; va_copy(event.va, va); bzLoggerStdOutCallback(&event); va_end(event.va); } for (int i = 0; i < BZ_LOGGER_MAX_CALLBACKS; ++i) { BzLoggerCallback cb = BZ_GET_LOGGER_MODULE()->callbacks[i]; if (!cb.callback) break; if (level >= cb.level) { event.userData = cb.userData; va_copy(event.va, va); cb.callback(&event); va_end(event.va); } } } void bzLoggerOnlyLog(BzLoggerLevel level, const char *fmt, ...) { va_list args; va_start(args, fmt); bzLoggerOnlyLogV(level, fmt, args); va_end(args); } void bzLoggerOnlyLogV(BzLoggerLevel level, const char *fmt, va_list va) { bzLoggerLogV(level, NULL, -1, fmt, va); } bool bzLoggerAddFP(void *fp, BzLoggerLevel level) { return bzLoggerAddCB(&(BzLoggerCallback) { .callback = bzLoggerFileCallback, .level = level, .userData = fp }); } bool bzLoggerAddCB(const BzLoggerCallback *callback) { for (int i = 0; i < BZ_LOGGER_MAX_CALLBACKS; ++i) { BzLoggerCallback *cbSlot = &BZ_GET_LOGGER_MODULE()->callbacks[i]; if (cbSlot->callback == NULL) { *cbSlot = *callback; return true; } } return false; }