#include #include "Logger.hpp" #include "../Hooks/Hooks.hpp" // HACK: namespace Aurora::Console::Logging { static AuList> gLogTasks; static AuThreadPrimitives::SpinLock gGlobalSpin; static AuList gFlushableLoggers; Logger::Logger(const AuList> &sinks) : sinks(sinks) { AuMemset(shouldFilter, 0, sizeof(shouldFilter)); { AU_LOCK_GUARD(gGlobalSpin); AuTryInsert(gFlushableLoggers, this); } } Logger::~Logger() { Disable(); } void Logger::WriteLines(AuUInt8 level, const ConsoleMessage &msg) { try { if (msg.line.find('\n') == AuString::npos) [[likely]] { AddToPushQueue(level, msg); WriteNow(level, msg); } else [[unlikely]] { Parse::SplitNewlines(msg.line, [&](const AuString &line) { ConsoleMessage dup = msg; dup.line = line; AddToPushQueue(level, dup); WriteNow(level, dup); }); } } catch (...) { // Loggers experiencing something fucky is a liablity Hooks::WriteLoggerFailedWarning(); } } void Logger::WriteMessage(AuUInt8 level, const ConsoleMessage &msg) { // Accounts for atomic shutdown { AU_LOCK_GUARD(spin); if (shouldFilter[level]) { return; } } WriteLines(level, msg); } void Logger::AddToPushQueue(AuUInt8 level, const ConsoleMessage &msg) { AU_LOCK_GUARD(gGlobalSpin); while (!AuTryInsert(gLogTasks, AuMakeTuple(this, level, msg))) { SysPushErrorMem("Push failed - trying again"); spin.Unlock(); AuThreading::Sleep(100); spin.Lock(); } } void Logger::PushFilter(AuUInt8 level, bool shouldFilter) { AU_LOCK_GUARD(spin); try { while (!AuTryInsert(filters, AuMakeTuple(level, shouldFilter))) { SysPushErrorMem("Push failed - trying again. wont be able to handle pop - wont syspanic yet"); AuThreading::Sleep(100); } AuMemset(this->shouldFilter, 0, sizeof(this->shouldFilter)); for (auto &tuple : filters) { auto level = std::get<0>(tuple); auto shouldFilter = std::get<1>(tuple); this->shouldFilter[level] = shouldFilter; } } catch (...) { } } void Logger::PopFilter() { try { AU_LOCK_GUARD(spin); filters.pop_back(); } catch (...) { } } void ForceFlushLoggers() { AU_LOCK_GUARD(gGlobalSpin); decltype(gLogTasks) logTasks; try { logTasks = AuExchange(gLogTasks, {}); } catch (...) { } if (logTasks.empty()) { return; } try { for (const auto &logEntry : logTasks) { auto &logger = std::get<0>(logEntry); auto &level = std::get<1>(logEntry); auto &message = std::get<2>(logEntry); logger->WriteLater(level, message); } } catch (...) { } for (const auto &logger : gFlushableLoggers) { for (const auto &sink : logger->sinks) { try { sink->OnFlush(); } catch (...) { SysPushErrorGeneric("..."); } } } } void Logger::Disable() { { AU_LOCK_GUARD(spin); AuMemset(shouldFilter, 1, sizeof(shouldFilter)); } { AU_LOCK_GUARD(gGlobalSpin); AuTryDeleteList(gFlushableLoggers, this); } ForceFlushLoggers(); } void Logger::WriteNow(AuUInt8 level, const ConsoleMessage &msg) { try { for (const auto &sink : this->sinks) { try { sink->OnMessageNonblocking(level, msg); } catch (...) { SysPushErrorGeneric("Failed to pump a logger"); } } } catch (...) { } } void Logger::WriteLater(AuUInt8 level, const ConsoleMessage &msg) { try { for (const auto &sink : this->sinks) { try { sink->OnMessageBlocking(level, msg); } catch (...) { SysPushErrorGeneric("Failed to pump a logger"); } } } catch (...) { } } void InitLoggers() { } void DeinitLoggers() { ForceFlushLoggers(); } AUKN_SYM ILogger *NewLoggerNew(const AuList> &sinks) { try { auto logger = _new Logger(sinks); if (!logger) { return nullptr; } return logger; } catch (...) { return {}; } } AUKN_SYM void NewLoggerRelease(ILogger *logger) { SafeDelete(logger); } }