#include "raid/core/log.hpp" #include #include #include namespace raid::log { namespace { std::atomic g_level{static_cast(Level::info)}; std::mutex g_mutex; Sink g_sink; const char* name(Level l) { switch (l) { case Level::trace: return "TRACE"; case Level::debug: return "DEBUG"; case Level::info: return "INFO"; case Level::warn: return "WARN"; case Level::error: return "ERROR"; default: return "OFF"; } } } // namespace void set_level(Level l) { g_level.store(static_cast(l)); } Level level() { return static_cast(g_level.load()); } void set_sink(Sink s) { std::lock_guard lk(g_mutex); g_sink = std::move(s); } std::string redact(std::string_view s) { static const std::regex re(R"((Bearer\s+)[A-Za-z0-9._\-]+|fd_[A-Za-z0-9]+\.[A-Za-z0-9_\-]+|(api[_-]?key=)[^&\s]+|(userid=)[^&\s]+)", std::regex::icase); return std::regex_replace(std::string(s), re, "$1$2$3"); } void emit(Level l, std::string_view msg, Fields fields) { if (static_cast(l) < g_level.load()) return; std::lock_guard lk(g_mutex); if (g_sink) { g_sink(l, msg, fields); return; } std::string line = std::string(name(l)) + " " + redact(msg); for (auto& [k, v] : fields) line += " " + k + "=" + redact(v); std::fprintf(stderr, "%s\n", line.c_str()); } } // namespace raid::log