#pragma once #include "RingBuffer.hpp" #include #include #include #include // NOTE: we keep this on one line so std::soruce_location reports the correct information #define GENERIC_LOG(lvl, fmtString, ...) Log::Add(Log::Message{ .level = lvl, .time = std::chrono::system_clock::now(), .srcLoc = std::source_location::current(), .text = fmt::format(fmtString __VA_OPT__(, ) __VA_ARGS__) }) #define LOG_DEBUG(...) GENERIC_LOG(Log::MessageLevel::Debug, __VA_ARGS__) #define LOG_INFO(...) GENERIC_LOG(Log::MessageLevel::Info, __VA_ARGS__) #define LOG_WARNING(...) GENERIC_LOG(Log::MessageLevel::Warning, __VA_ARGS__) #define LOG_ERROR(...) GENERIC_LOG(Log::MessageLevel::Error, __VA_ARGS__) namespace Log { enum class MessageLevel { Debug, Info, Warning, Error, }; struct Message { MessageLevel level; std::chrono::time_point time; std::source_location srcLoc; std::string text; }; /// A mRing buffer of log messages for programmatic inspection at runtime. struct MessageBuffer { RingBuffer messages; }; /// Unique ID identifying a currently registered MessageBuffer. using MessageBufferId = int; MessageBufferId RegisterBuffer(MessageBuffer& buffer); void UnregisterBuffer(MessageBufferId id); MessageBuffer* GetBuffer(MessageBufferId id); void DumpRegisteredBuffers(); extern bool gPrintToStdOut; #if BRUSSEL_DEV_ENV // NOTE: initialized in main.cpp extern MessageBuffer gDefaultBuffer; extern MessageBufferId gDefaultBufferId; #endif // TODO improve this interface: don't copy std::string when there is in fact no MessageBuffer registered void Add(const Message& msg); } // namespace Log