#include "debug.h" #include #include #include debug_level_t g_debug_level = DEBUG_LEVEL_NONE; static FILE* g_debug_file = NULL; static void debug_open_log_file(void) { if (g_debug_file) return; const char* path = getenv("DIDACTYL_LOG_FILE"); if (!path || path[0] == '\0') { path = "debug.log"; } g_debug_file = fopen(path, "a"); if (g_debug_file) { setvbuf(g_debug_file, NULL, _IOLBF, 0); } } void debug_init(int level) { if (level < 0) level = 0; if (level > 5) level = 5; g_debug_level = (debug_level_t)level; debug_open_log_file(); } void debug_log(debug_level_t level, const char* file, int line, const char* format, ...) { time_t now = time(NULL); struct tm* tm_info = localtime(&now); char timestamp[32]; strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info); const char* level_str = "UNKNOWN"; switch (level) { case DEBUG_LEVEL_ERROR: level_str = "ERROR"; break; case DEBUG_LEVEL_WARN: level_str = "WARN "; break; case DEBUG_LEVEL_INFO: level_str = "INFO "; break; case DEBUG_LEVEL_DEBUG: level_str = "DEBUG"; break; case DEBUG_LEVEL_TRACE: level_str = "TRACE"; break; default: break; } printf("[%s] [%s] ", timestamp, level_str); if (g_debug_file) { fprintf(g_debug_file, "[%s] [%s] ", timestamp, level_str); } if (file && g_debug_level >= DEBUG_LEVEL_TRACE) { const char* filename = strrchr(file, '/'); filename = filename ? filename + 1 : file; printf("[%s:%d] ", filename, line); if (g_debug_file) { fprintf(g_debug_file, "[%s:%d] ", filename, line); } } va_list args; va_start(args, format); vprintf(format, args); va_end(args); if (g_debug_file) { va_list args_file; va_start(args_file, format); vfprintf(g_debug_file, format, args_file); va_end(args_file); } printf("\n"); fflush(stdout); if (g_debug_file) { fprintf(g_debug_file, "\n"); fflush(g_debug_file); } }