377 lines
8.3 KiB
C++
377 lines
8.3 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuLogger.cpp
|
|
Date: 2022-1-21
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuLogger.hpp"
|
|
#include <Source/Grug/AuGrug.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);
|
|
SysAssert(AuTryInsert(gFlushableLoggers, this));
|
|
}
|
|
}
|
|
|
|
Logger::~Logger()
|
|
{
|
|
Disable();
|
|
}
|
|
|
|
void Logger::WriteLines(AuUInt8 uLevel, const ConsoleMessage &msg)
|
|
{
|
|
try
|
|
{
|
|
if (msg.line.find('\n') == AuString::npos) [[likely]]
|
|
{
|
|
if (WriteNow(uLevel, msg))
|
|
{
|
|
AddToPushQueue(uLevel, msg);
|
|
}
|
|
|
|
}
|
|
else [[unlikely]]
|
|
{
|
|
Parse::SplitNewlines(msg.line,
|
|
[&](const AuString &line)
|
|
{
|
|
ConsoleMessage dup = msg;
|
|
dup.line = line;
|
|
|
|
if (WriteNow(uLevel, dup))
|
|
{
|
|
AddToPushQueue(uLevel, dup);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
// Loggers experiencing something fucky is a liablity
|
|
Hooks::WriteLoggerFailedWarning();
|
|
}
|
|
}
|
|
|
|
void Logger::WriteMessage(AuUInt8 uLevel, const ConsoleMessage &msg)
|
|
{
|
|
|
|
// Accounts for atomic shutdown
|
|
{
|
|
AU_LOCK_GUARD(spin);
|
|
|
|
if (shouldFilter[uLevel])
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
WriteLines(uLevel, msg);
|
|
}
|
|
|
|
void Logger::AddToPushQueue(AuUInt8 uLevel, 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, uLevel, msg)))
|
|
{
|
|
SysPushErrorMem("Push failed - trying again");
|
|
spin.Unlock();
|
|
AuThreading::Sleep(100);
|
|
spin.Lock();
|
|
}
|
|
}
|
|
|
|
Grug::DrachenlordScreech();
|
|
}
|
|
|
|
void Logger::PushFilter(AuUInt8 uLevel, bool bShouldFilter)
|
|
{
|
|
AU_LOCK_GUARD(spin);
|
|
|
|
try
|
|
{
|
|
while (!AuTryInsert(filters, AuMakeTuple(uLevel, 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 uLevel = AuGet<0>(tuple);
|
|
auto shouldFilter = AuGet<1>(tuple);
|
|
this->shouldFilter[uLevel] = shouldFilter;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
|
|
void Logger::PopFilter()
|
|
{
|
|
AU_LOCK_GUARD(this->spin);
|
|
this->filters.pop_back();
|
|
}
|
|
|
|
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 &uLevel = AuGet<1>(logEntry);
|
|
auto &message = AuGet<2>(logEntry);
|
|
|
|
logger->WriteLater(uLevel, 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 &uLevel = AuGet<1>(logEntry);
|
|
auto &message = AuGet<2>(logEntry);
|
|
|
|
logger->WriteLater(uLevel, 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 uLevel, const ConsoleMessage &msg)
|
|
{
|
|
bool ret {};
|
|
try
|
|
{
|
|
for (const auto &sink : this->sinks)
|
|
{
|
|
if (!sink)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
ret |= sink->OnMessageNonblocking(uLevel, msg);
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch("Failed to pump a logger");
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
ret = true;
|
|
SysPushErrorCatch();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void Logger::WriteLater(AuUInt8 uLevel, const ConsoleMessage &msg)
|
|
{
|
|
try
|
|
{
|
|
for (const auto &sink : this->sinks)
|
|
{
|
|
if (!sink)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
sink->OnMessageBlocking(uLevel, 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 pLogger = _new Logger(sinks);
|
|
if (!pLogger)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
return pLogger;
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch();
|
|
return {};
|
|
}
|
|
}
|
|
|
|
AUKN_SYM void NewLoggerRelease(ILogger *pLogger)
|
|
{
|
|
AuSafeDelete<Logger *>(pLogger);
|
|
}
|
|
} |