#include "Log.hpp" #include "Macros.hpp" #include #include #include namespace ProjectBrussel_UNITY_ID { using namespace Log; const char* MapMessageLevelToString(MessageLevel level) { switch (level) { using enum MessageLevel; case Debug: return "DEBUG"; case Info: return "INFO"; case Warning: return "WARN"; case Error: return "ERROR"; default: UNREACHABLE; } } void PrintMessage(const Message& msg) { using namespace std::chrono; auto t = system_clock::to_time_t(msg.time); char timeStr[128]; strftime(timeStr, sizeof(timeStr), "%H:%M:%S", localtime(&t)); printf("[%s][%s][%s:%u] %.*s\n", MapMessageLevelToString(msg.level), timeStr, msg.srcLoc.function_name(), msg.srcLoc.line(), PRINTF_STRING_VIEW(msg.text)); } MessageBufferId gNextBufferId = 0; robin_hood::unordered_map gBuffers; } // namespace ProjectBrussel_UNITY_ID namespace Log { bool gPrintToStdOut = true; #if BRUSSEL_DEV_ENV MessageBuffer gDefaultBuffer; MessageBufferId gDefaultBufferId; #endif } // namespace Log Log::MessageBufferId Log::RegisterBuffer(MessageBuffer& buffer) { using namespace ProjectBrussel_UNITY_ID; auto id = gNextBufferId++; gBuffers.try_emplace(id, &buffer); return id; } void Log::UnregisterBuffer(MessageBufferId id) { using namespace ProjectBrussel_UNITY_ID; gBuffers.erase(id); } Log::MessageBuffer* Log::GetBuffer(MessageBufferId id) { using namespace ProjectBrussel_UNITY_ID; auto iter = gBuffers.find(id); if (iter != gBuffers.end()) { return iter->second; } else { return nullptr; } } void Log::DumpRegisteredBuffers() { using namespace ProjectBrussel_UNITY_ID; puts("================ BEGIN LOG BUFFER DUMP ================"); for (const auto& [id, buffer] : gBuffers) { printf("Buffer #%d at %p\n", id, buffer); printf("Buffer size: %zu\n", buffer->messages.capacity()); bool needsWrapAround = buffer->messages.GetHeadIdx() >= buffer->messages.GetTailIdx(); if (needsWrapAround) { printf("Fill size: %zu in [%zu,%zu) and [0,%zu)\n", buffer->messages.size(), // First chunk: [begin,end) buffer->messages.GetHeadIdx(), buffer->messages.capacity(), // Second chunk: [0,end) buffer->messages.GetTailIdx()); } else { printf("Fill size: %zu in [%zu,%zu)\n", buffer->messages.size(), // [begin,end) buffer->messages.GetHeadIdx(), buffer->messages.GetTailIdx()); } for (const auto& msg : buffer->messages) { // Indent log messages in this buffer printf("\t"); PrintMessage(msg); } } puts("================ END LOG BUFFER DUMP ================"); } void Log::Add(const Message& msg) { using namespace ProjectBrussel_UNITY_ID; if (gPrintToStdOut) { PrintMessage(msg); } for (auto& [_, buffer] : gBuffers) { buffer->messages.push_back(msg); } }