/** * Debug configuration implementation * Runtime debug configuration system for flexible debug output control */ #include "debug_config.h" #include #include #include #include #include #include #include /* Global debug configuration */ debug_config_t g_debug_config = { .level = DEBUG_LEVEL_ERROR, .categories = DEBUG_CATEGORY_ALL, .timestamp_enabled = 1, .function_name_enabled = 1, .file_line_enabled = 1, .color_enabled = 1, .max_output_per_second = 0, .output_file = NULL }; /* Output file handle */ FILE* debug_output_file = NULL; /* Rate limiting */ static size_t output_count = 0; static time_t last_output_time = 0; static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; /* ANSI color codes */ static const char* color_red = "\033[31m"; static const char* color_yellow = "\033[33m"; static const char* color_green = "\033[32m"; static const char* color_blue = "\033[34m"; static const char* color_magenta = "\033[35m"; static const char* color_cyan = "\033[36m"; static const char* color_reset = "\033[0m"; /* Initialize debug system with default settings */ void debug_config_init(void) { pthread_mutex_lock(&debug_mutex); g_debug_config.level = DEBUG_LEVEL_ERROR; g_debug_config.categories = DEBUG_CATEGORY_ALL; g_debug_config.timestamp_enabled = 1; g_debug_config.function_name_enabled = 1; g_debug_config.file_line_enabled = 1; g_debug_config.color_enabled = 1; g_debug_config.max_output_per_second = 0; g_debug_config.output_file = NULL; if (debug_output_file && debug_output_file != stderr && debug_output_file != stdout) { fclose(debug_output_file); } debug_output_file = stderr; output_count = 0; last_output_time = 0; pthread_mutex_unlock(&debug_mutex); } /* Set debug level */ void debug_set_level(debug_level_t level) { pthread_mutex_lock(&debug_mutex); g_debug_config.level = level; pthread_mutex_unlock(&debug_mutex); } /* Enable/disable specific categories */ void debug_enable_category(debug_category_t category) { pthread_mutex_lock(&debug_mutex); g_debug_config.categories |= category; pthread_mutex_unlock(&debug_mutex); } void debug_disable_category(debug_category_t category) { pthread_mutex_lock(&debug_mutex); g_debug_config.categories &= ~category; pthread_mutex_unlock(&debug_mutex); } void debug_set_categories(uint32_t categories) { pthread_mutex_lock(&debug_mutex); g_debug_config.categories = categories; pthread_mutex_unlock(&debug_mutex); } /* Configure output options */ void debug_enable_timestamp(int enable) { pthread_mutex_lock(&debug_mutex); g_debug_config.timestamp_enabled = enable; pthread_mutex_unlock(&debug_mutex); } void debug_enable_function_name(int enable) { pthread_mutex_lock(&debug_mutex); g_debug_config.function_name_enabled = enable; pthread_mutex_unlock(&debug_mutex); } void debug_enable_file_line(int enable) { pthread_mutex_lock(&debug_mutex); g_debug_config.file_line_enabled = enable; pthread_mutex_unlock(&debug_mutex); } void debug_enable_color(int enable) { pthread_mutex_lock(&debug_mutex); g_debug_config.color_enabled = enable; pthread_mutex_unlock(&debug_mutex); } void debug_set_rate_limit(size_t max_per_second) { pthread_mutex_lock(&debug_mutex); g_debug_config.max_output_per_second = max_per_second; pthread_mutex_unlock(&debug_mutex); } void debug_set_output_file(const char* file_path) { pthread_mutex_lock(&debug_mutex); if (file_path == NULL) { if (debug_output_file && debug_output_file != stderr && debug_output_file != stdout) { fclose(debug_output_file); } debug_output_file = stderr; g_debug_config.output_file = NULL; } else { FILE* new_file = fopen(file_path, "a"); if (new_file) { if (debug_output_file && debug_output_file != stderr && debug_output_file != stdout) { fclose(debug_output_file); } debug_output_file = new_file; g_debug_config.output_file = file_path; } } pthread_mutex_unlock(&debug_mutex); } /* Check if debug output should be shown for given level and category */ int debug_should_output(debug_level_t level, debug_category_t category) { pthread_mutex_lock(&debug_mutex); /* Check if category is enabled */ if (!(g_debug_config.categories & category)) { pthread_mutex_unlock(&debug_mutex); return 0; } /* Check if level is sufficient */ if (level > g_debug_config.level) { pthread_mutex_unlock(&debug_mutex); return 0; } /* Rate limiting check */ if (g_debug_config.max_output_per_second > 0) { time_t current_time = time(NULL); if (current_time != last_output_time) { output_count = 0; last_output_time = current_time; } if (output_count >= g_debug_config.max_output_per_second) { pthread_mutex_unlock(&debug_mutex); return 0; } output_count++; } pthread_mutex_unlock(&debug_mutex); return 1; } /* Get current debug level for a category */ debug_level_t debug_get_effective_level(debug_category_t category) { pthread_mutex_lock(&debug_mutex); debug_level_t level = g_debug_config.level; pthread_mutex_unlock(&debug_mutex); return level; } /* Get color for debug level */ static const char* get_level_color(debug_level_t level) { if (!g_debug_config.color_enabled) { return ""; } switch (level) { case DEBUG_LEVEL_ERROR: return color_red; case DEBUG_LEVEL_WARN: return color_yellow; case DEBUG_LEVEL_INFO: return color_green; case DEBUG_LEVEL_DEBUG: return color_blue; case DEBUG_LEVEL_TRACE: return color_magenta; default: return ""; } } /* Get level name */ static const char* get_level_name(debug_level_t level) { switch (level) { case DEBUG_LEVEL_ERROR: return "ERROR"; case DEBUG_LEVEL_WARN: return "WARN"; case DEBUG_LEVEL_INFO: return "INFO"; case DEBUG_LEVEL_DEBUG: return "DEBUG"; case DEBUG_LEVEL_TRACE: return "TRACE"; default: return "UNKNOWN"; } } /* Format and output debug message */ void debug_output(debug_level_t level, debug_category_t category, const char* function, const char* file, int line, const char* format, ...) { pthread_mutex_lock(&debug_mutex); va_list args; FILE* output = debug_output_file ? debug_output_file : stderr; /* Print timestamp if enabled */ if (g_debug_config.timestamp_enabled) { time_t now = time(NULL); struct tm* tm_info = localtime(&now); char time_str[32]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); fprintf(output, "[%s] ", time_str); } /* Print level and color */ if (g_debug_config.color_enabled) { fprintf(output, "%s[%s]%s ", get_level_color(level), get_level_name(level), color_reset); } else { fprintf(output, "[%s] ", get_level_name(level)); } /* Print category */ fprintf(output, "[%d] ", category); /* Print function name if enabled */ if (g_debug_config.function_name_enabled && function) { fprintf(output, "%s() ", function); } /* Print file:line if enabled */ if (g_debug_config.file_line_enabled && file) { fprintf(output, "(%s:%d) ", file, line); } /* Print the actual message */ va_start(args, format); vfprintf(output, format, args); va_end(args); fprintf(output, "\n"); fflush(output); pthread_mutex_unlock(&debug_mutex); } /* Stub implementations for advanced features */ int debug_parse_config(const char* config_string) { /* Simple parser - for now just return success */ return 0; } int debug_parse_config_file(const char* file_path) { /* Stub implementation */ return 0; } int debug_enable_config_reload(const char* file_path, int interval_seconds) { /* Stub implementation */ return 0; }