#include "log.h" #include sd_log_level_t log_level = SD_LOG_INFO; bool log_color = false; std::string sd_basename(const std::string& path) { size_t pos = path.find_last_of('/'); if (pos != std::string::npos) { return path.substr(pos + 1); } pos = path.find_last_of('\\'); if (pos != std::string::npos) { return path.substr(pos + 1); } return path; } void print_utf8(FILE* stream, const char* utf8) { if (!utf8) { return; } #ifdef _WIN32 HANDLE h = (stream == stderr) ? GetStdHandle(STD_ERROR_HANDLE) : GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode; BOOL is_console = GetConsoleMode(h, &mode); if (is_console) { int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); if (wlen <= 0) { return; } std::vector wbuf(static_cast(wlen)); MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wbuf.data(), wlen); DWORD written; WriteConsoleW(h, wbuf.data(), wlen - 1, &written, NULL); } else { DWORD written; WriteFile(h, utf8, (DWORD)strlen(utf8), &written, NULL); } #else fputs(utf8, stream); #endif } const char* log_level_name(sd_log_level_t level) { switch (level) { case SD_LOG_DEBUG: return "debug"; case SD_LOG_VERBOSE: return "verbose"; case SD_LOG_INFO: return "info"; case SD_LOG_WARN: return "warn"; case SD_LOG_ERROR: return "error"; default: return "unknown"; } } bool parse_log_level(const std::string& name, sd_log_level_t& level) { const sd_log_level_t levels[] = {SD_LOG_DEBUG, SD_LOG_VERBOSE, SD_LOG_INFO, SD_LOG_WARN, SD_LOG_ERROR}; for (sd_log_level_t candidate : levels) { if (name == log_level_name(candidate)) { level = candidate; return true; } } return false; } void log_print(enum sd_log_level_t level, const char* log, sd_log_level_t min_level, bool color) { int tag_color; const char* level_str; FILE* out_stream = (level == SD_LOG_ERROR) ? stderr : stdout; if (!log || level < min_level) { return; } switch (level) { case SD_LOG_DEBUG: tag_color = 37; level_str = "DEBUG"; break; case SD_LOG_VERBOSE: tag_color = 37; level_str = "VERBOSE"; break; case SD_LOG_INFO: tag_color = 34; level_str = "INFO"; break; case SD_LOG_WARN: tag_color = 35; level_str = "WARN"; break; case SD_LOG_ERROR: tag_color = 31; level_str = "ERROR"; break; default: tag_color = 33; level_str = "?????"; break; } if (color) { fprintf(out_stream, "\033[%d;1m[%-7s]\033[0m ", tag_color, level_str); } else { fprintf(out_stream, "[%-7s] ", level_str); } fflush(out_stream); print_utf8(out_stream, log); fflush(out_stream); } void example_log_printf(sd_log_level_t level, const char* file, int line, const char* format, ...) { constexpr size_t LOG_BUFFER_SIZE = 4096; va_list args; va_start(args, format); static char log_buffer[LOG_BUFFER_SIZE + 1]; int written = snprintf(log_buffer, LOG_BUFFER_SIZE, "%s:%-4d - ", sd_basename(file).c_str(), line); if (written >= 0 && written < static_cast(LOG_BUFFER_SIZE)) { vsnprintf(log_buffer + written, LOG_BUFFER_SIZE - written, format, args); } size_t len = strlen(log_buffer); if (len == 0 || log_buffer[len - 1] != '\n') { strncat(log_buffer, "\n", LOG_BUFFER_SIZE - len); } log_print(level, log_buffer, log_level, log_color); va_end(args); }