AuroraRuntime/Source/Logging/Logger.cpp
2022-03-31 04:40:19 +01:00

384 lines
8.3 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Logger.cpp
Date: 2022-1-21
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "Logger.hpp"
#include <Source/Grug/Grug.hpp>
#include <Source/Console/Hooks/Hooks.hpp>
namespace Aurora::Logging
{
using namespace Console;
static AuList<AuTuple<Logger *, AuUInt8, ConsoleMessage>> gLogTasks;
static AuThreadPrimitives::SpinLock gGlobalSpin;
static AuThreadPrimitives::SpinLock gTaskSpin;
static AuList<Logger *> gFlushableLoggers;
Logger::Logger(const AuList<AuSPtr<IBasicSink>> &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]]
{
if (WriteNow(level, msg))
{
AddToPushQueue(level, msg);
}
}
else [[unlikely]]
{
Parse::SplitNewlines(msg.line,
[&](const AuString &line)
{
ConsoleMessage dup = msg;
dup.line = line;
if (WriteNow(level, dup))
{
AddToPushQueue(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(gTaskSpin);
auto nice = gLogTasks.size() + 1;
if (gLogTasks.capacity() < nice)
{
gLogTasks.reserve(nice*10);
}
while (!AuTryInsert(gLogTasks, AuMakeTuple(this, level, msg)))
{
SysPushErrorMem("Push failed - trying again");
spin.Unlock();
AuThreading::Sleep(100);
spin.Lock();
}
}
Grug::DrachenlordScreech();
}
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 = AuGet<0>(tuple);
auto shouldFilter = AuGet<1>(tuple);
this->shouldFilter[level] = shouldFilter;
}
}
catch (...)
{
}
}
void Logger::PopFilter()
{
try
{
AU_LOCK_GUARD(spin);
filters.pop_back();
}
catch (...)
{
}
}
void ForceFlushLoggers()
{
decltype(gLogTasks) logTasks;
AU_LOCK_GUARD(gGlobalSpin);
{
AU_LOCK_GUARD(gTaskSpin);
try
{
if (AuTryResize(logTasks, gLogTasks.size()))
{
for (int i = 0; i < gLogTasks.size(); i++)
{
logTasks[i] = AuMove(gLogTasks[i]);
}
gLogTasks.clear();
}
}
catch (...)
{
}
if (logTasks.empty())
{
return;
}
}
try
{
for (const auto &logEntry : logTasks)
{
auto &logger = AuGet<0>(logEntry);
auto &level = AuGet<1>(logEntry);
auto &message = AuGet<2>(logEntry);
logger->WriteLater(level, message);
}
}
catch (...)
{
}
}
void ForceFlushLoggersNoLock()
{
decltype(gLogTasks) logTasks;
{
try
{
if (AuTryResize(logTasks, gLogTasks.size()))
{
for (int i = 0; i < gLogTasks.size(); i++)
{
logTasks[i] = AuMove(gLogTasks[i]);
}
gLogTasks.clear();
}
}
catch (...)
{
}
if (logTasks.empty())
{
return;
}
}
try
{
for (const auto &logEntry : logTasks)
{
auto &logger = AuGet<0>(logEntry);
auto &level = AuGet<1>(logEntry);
auto &message = AuGet<2>(logEntry);
logger->WriteLater(level, message);
}
}
catch (...)
{
}
}
static void ForceFlushLogger(Logger *logger)
{
for (const auto &sink : logger->sinks)
{
if (!sink)
{
continue;
}
try
{
sink->OnFlush();
}
catch (...)
{
SysPushErrorCatch();
}
}
}
void ForceFlushFlushNoLock()
{
for (const auto &logger : gFlushableLoggers)
{
ForceFlushLogger(logger);
}
}
void ForceFlushFlush()
{
AU_LOCK_GUARD(gGlobalSpin);
ForceFlushFlushNoLock();
}
void Logger::Disable()
{
AU_LOCK_GUARD(gGlobalSpin);
ForceFlushLoggersNoLock();
ForceFlushLogger(this);
{
AU_LOCK_GUARD(spin);
AuMemset(shouldFilter, 1, sizeof(shouldFilter));
}
{
AuTryRemove(gFlushableLoggers, this);
}
}
bool Logger::WriteNow(AuUInt8 level, const ConsoleMessage &msg)
{
bool ret {};
try
{
for (const auto &sink : this->sinks)
{
if (!sink)
{
continue;
}
try
{
ret |= sink->OnMessageNonblocking(level, msg);
}
catch (...)
{
SysPushErrorCatch("Failed to pump a logger");
}
}
}
catch (...)
{
ret = true;
SysPushErrorCatch();
}
return ret;
}
void Logger::WriteLater(AuUInt8 level, const ConsoleMessage &msg)
{
try
{
for (const auto &sink : this->sinks)
{
if (!sink)
{
continue;
}
try
{
sink->OnMessageBlocking(level, msg);
}
catch (...)
{
SysPushErrorCatch("Failed to pump a logger");
}
}
}
catch (...)
{
SysPushErrorCatch();
}
}
void InitLoggers()
{
gLogTasks.reserve(1000);
}
void DeinitLoggers()
{
ForceFlushLoggers();
gUserLogger.reset();
}
AUKN_SYM ILogger *NewLoggerNew(const AuList<AuSPtr<IBasicSink>> &sinks)
{
try
{
auto logger = _new Logger(sinks);
if (!logger)
{
return nullptr;
}
return logger;
}
catch (...)
{
SysPushErrorCatch();
return {};
}
}
AUKN_SYM void NewLoggerRelease(ILogger *logger)
{
AuSafeDelete<Logger *>(logger);
}
}