#pragma once #include #include // New API — use these going forward. namespace nxst::log { enum class Level { Debug, Info, Warn, Error }; void write(Level level, const char* fmt, ...) __attribute__((format(printf, 2, 3))); void debug(const char* fmt, ...) __attribute__((format(printf, 1, 2))); void info(const char* fmt, ...) __attribute__((format(printf, 1, 2))); void warn(const char* fmt, ...) __attribute__((format(printf, 1, 2))); void error(const char* fmt, ...) __attribute__((format(printf, 1, 2))); // No-op: writes are immediate. Kept for source compatibility during migration. inline void flush() {} } // namespace nxst::log // Backward-compat shim — existing Logger::getInstance().log(...) call sites compile // unchanged. Format args are dropped (same behavior as broken original). Migrate // call sites to nxst::log::* in Phase 3. struct Logger { static Logger& getInstance() { static Logger instance; return instance; } // clang-tidy naming suppressed: these must match existing call sites during migration. static constexpr const char* INFO = "[INFO]"; // NOLINT(readability-identifier-naming) static constexpr const char* DEBUG = "[DEBUG]"; // NOLINT(readability-identifier-naming) static constexpr const char* ERROR = "[ERROR]"; // NOLINT(readability-identifier-naming) static constexpr const char* WARN = "[WARN]"; // NOLINT(readability-identifier-naming) static void flush() { nxst::log::flush(); } // Args intentionally dropped — format string still logged for visibility. template void log(const std::string& level, const std::string& fmt, Args&&... /*args*/) { if (level == ERROR) nxst::log::error("%s", fmt.c_str()); else if (level == WARN) nxst::log::warn("%s", fmt.c_str()); else if (level == DEBUG) nxst::log::debug("%s", fmt.c_str()); else nxst::log::info("%s", fmt.c_str()); } Logger() = default; ~Logger() = default; Logger(const Logger&) = delete; // NOLINT(modernize-use-equals-delete) Logger& operator=(const Logger&) = delete; // NOLINT(modernize-use-equals-delete) };