← Back to file list Raw

src/CLogger.cpp

#include "CLogger.h"
#include "CEngine.h"
#include "CTerminal.h"
#include "CFunction.h"
#include "CStartupArgsManager.h"
#include "CConVarManager.h"
#include "CWrapable.h"
#include <future>
#include <chrono>
#include <thread>
std::wofstream* CLogger::m_OpenStream(std::string path)
{
if (streams.find(path) == streams.end())
{
std::wofstream wf;
wf.open(path, std::ios::app | std::ios::out);
if (!wf.is_open()) { return nullptr; }
streams[path] = std::move(wf);
}
return &streams[path];
}
bool CLogger::V_Init()
{
std::string outPath, errPath, slowModeDelay;
bool notasync = false;
bool forceasync = false;
bool nofiles = false;
COMPONENT_CALL_GET(outPath, CStartupArgsManager, GetArgumentValue("-out"));
COMPONENT_CALL_GET(errPath, CStartupArgsManager, GetArgumentValue("-err"));
COMPONENT_CALL_GET(slowModeDelay, CStartupArgsManager, GetArgumentValue("-slowloggerdelay"));
COMPONENT_CALL_GET(notasync, CStartupArgsManager, IsArgumentSet("-synclogger"));
COMPONENT_CALL_GET(forceasync, CStartupArgsManager, IsArgumentSet("-asynclogger"));
COMPONENT_CALL_GET(nofiles, CStartupArgsManager, IsArgumentSet("-loggernofiles"));
COMPONENT_CALL_GET(m_slowMode, CStartupArgsManager, IsArgumentSet("-slowlogger"));
if(m_slowMode && !slowModeDelay.empty())
{
m_slowModeDelay = StringUtils::FromStr<unsigned int>(slowModeDelay);
}
if(notasync) { m_isAsync = false; }
if(forceasync) { m_isAsync = true; }
if(!nofiles)
{
outstream = m_OpenStream(outPath);
errstream = m_OpenStream(errPath);
}
if (m_isAsync)
{
outqueue.reserve(128);
errqueue.reserve(128);
m_thread = std::make_unique<std::thread>(&CLogger::m_ThreadedWorker, this);
}
return true;
}
void CLogger::V_PostInit()
{
auto mgr = CEngine::GetInstance()->Components.GetComponentTyped<CConVarManager>();
mgr->AddConVar("time.limit.logger.maxfps", new CWrapable<unsigned int>(20));
mgr->AddConVar("time.limit.logger.yield", new CWrapable<bool>(true));
mgr->AddConVar("time.limit.logger.adaptive_sleep", new CWrapable<bool>(true));
mgr->AddConVar("time.limit.logger.strict_sleep", new CWrapable<bool>(false));
}
void CLogger::V_Update()
{
if(CClock::now() - lastsync >= std::chrono::duration<float>(sync_datas_interval))
{
auto mgr = CEngine::GetInstance()->Components.GetComponentTyped<CConVarManager>();
async_data data;
data.adaptive_sleep = mgr->GetConVarValue<unsigned int>("time.limit.logger.maxfps");
data.yield = mgr->GetConVarValue<bool>("time.limit.logger.yield");
data.adaptive_sleep = mgr->GetConVarValue<bool>("time.limit.logger.adaptive_sleep");
data.strict_sleep = mgr->GetConVarValue<bool>("time.limit.logger.strict_sleep");
{
std::lock_guard _lock(async_data_mutex);
threaded_async = data;
}
lastsync = CClock::now();
}
}
CLogger::~CLogger()
{
if (m_isAsync)
{
AskedToStop.store(true, std::memory_order_relaxed);
while (!Stopped)
{
std::this_thread::yield();
}
if(m_thread->joinable())
{
m_thread->join();
}
}
if (outstream && outstream->is_open()) { outstream->flush(); outstream->close(); }
if (errstream && errstream->is_open()) { errstream->flush(); errstream->close(); }
}
void CLogger::m_flushOut(const std::wstring& str)
{
if (outstream && outstream->is_open())
{
(*outstream) << str;
outstream->flush();
}
if(!CEngine::GetInstance()->GetStopFlag())
{
COMPONENT_CALL(CTerminal, Print(str));
}
m_Wait();
}
void CLogger::m_flushErr(const std::wstring& err)
{
if (errstream && errstream->is_open())
{
(*errstream) << err;
errstream->flush();
}
if(!CEngine::GetInstance()->GetStopFlag())
{
COMPONENT_CALL(CTerminal, Error(err));
}
m_Wait();
}
void CLogger::Out(const std::wstring& str)
{
if (m_isAsync)
{
std::lock_guard lock(mutex);
outqueue.push_back(str);
}
else
{
m_flushOut(str);
}
OnOut(str);
}
void CLogger::Err(const std::wstring& err)
{
if (m_isAsync)
{
std::lock_guard lock(mutex);
errqueue.push_back(err);
}
else
{
m_flushErr(err);
}
OnErr(err);
}
void CLogger::Outln(const std::wstring& str)
{
Out(str + L"\n");
}
void CLogger::Errln(const std::wstring& err)
{
Err(err + L"\n");
}
void CLogger::SetAsync()
{
m_isAsync = true;
}
bool CLogger::IsAsync()
{
return m_isAsync;
}
void CLogger::m_ThreadedWorker()
{
std::vector<std::wstring> outcopy, errcopy;
while (true)
{
//mgr->AddConVar("time.limit.logger.maxfps", new CWrapable<unsigned int>(20));
//mgr->AddConVar("time.limit.logger.yield", new CWrapable<bool>(true));
//mgr->AddConVar("time.limit.logger.adaptive_sleep", new CWrapable<bool>(true));
//mgr->AddConVar("time.limit.logger.strict_sleep", new CWrapable<bool>(false));
async_data asdata;
{
std::lock_guard _lock(async_data_mutex);
asdata = threaded_async;
}
Sleeper.Start(asdata.maxfps);
{
std::lock_guard lock(mutex);
if(!outqueue.empty()) { outcopy.swap(outqueue); }
if(!errqueue.empty()) { errcopy.swap(errqueue); }
}
for (const auto& s : outcopy) { m_flushOut(s); }
for (const auto& e : errcopy) { m_flushErr(e); }
outcopy.clear();
errcopy.clear();
if (AskedToStop.load(std::memory_order_acquire))
{
Stopped.store(true, std::memory_order_release);
break;
}
Sleeper.End(asdata.yield, asdata.adaptive_sleep, asdata.strict_sleep);
}
}
bool CLogger::V_ScriptInit(std::shared_ptr<sol::state> state, sol::table table)
{
table.set_function("out", [this](const std::wstring& text) { Out(text); });
table.set_function("outln", [this](const std::wstring& text) { Outln(text); });
table.set_function("err", [this](const std::wstring& err) { Err(err); });
table.set_function("errln", [this](const std::wstring& err) { Errln(err); });
return true;
}
void CLogger::m_Wait() const
{
if(!m_slowMode) { return; }
std::this_thread::sleep_for(std::chrono::milliseconds(m_slowModeDelay));
}
sol::object CLogger::V_GetScriptUserType(sol::state_view state)
{
return sol::make_object(state, this);
}
LINK_COMPONENT_TO_CLASS(CLogger, logger);