#pragma once #include #include #include #include #include namespace aurora { void log_internal(AuroraLogLevel level, const char* module, const char* message, unsigned int len) noexcept; extern AuroraConfig g_config; struct Module { const char* name; explicit Module(const char* name) noexcept : name(name) {} template void report(const AuroraLogLevel level, fmt::format_string fmt, T&&... args) noexcept { if (g_config.logLevel > level) return; auto message = fmt::format(fmt, std::forward(args)...); log_internal(level, name, message.c_str(), static_cast(message.size())); } template void debug(fmt::format_string fmt, T&&... args) noexcept { report(LOG_DEBUG, fmt, std::forward(args)...); } template void info(fmt::format_string fmt, T&&... args) noexcept { report(LOG_INFO, fmt, std::forward(args)...); } template void warn(fmt::format_string fmt, T&&... args) noexcept { report(LOG_WARNING, fmt, std::forward(args)...); } template void error(fmt::format_string fmt, T&&... args) noexcept { report(LOG_ERROR, fmt, std::forward(args)...); } template [[noreturn]] void fatal(fmt::format_string fmt, T&&... args) noexcept { auto message = fmt::format(fmt, std::forward(args)...); log_internal(LOG_FATAL, name, message.c_str(), static_cast(message.size())); // Embedders can provide a fatal log callback, which the runtime uses for its own crash dialog. // Standalone Aurora builds fall back to logging.cpp's native one. if (g_config.logCallback == nullptr) { show_fatal_dialog(name, message); } std::abort(); } private: static void show_fatal_dialog(const char* module, std::string_view message) noexcept; }; } // namespace aurora template <> struct fmt::formatter : formatter { auto format(AuroraLogLevel level, format_context& ctx) const -> format_context::iterator; };