2021-06-27 21:25:29 +00:00
|
|
|
/***
|
|
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
File: ConsoleFIO.cpp
|
2021-06-27 21:25:29 +00:00
|
|
|
Date: 2021-6-22
|
|
|
|
Author: Reece
|
|
|
|
***/
|
|
|
|
#include <RuntimeInternal.hpp>
|
2021-09-06 10:58:08 +00:00
|
|
|
#include "ConsoleFIO.hpp"
|
2021-06-27 21:25:29 +00:00
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
namespace Aurora::Console::ConsoleFIO
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
|
|
|
static AuList<AuUInt8> gLogBuffer;
|
|
|
|
static Threading::Primitives::RWLockUnique_t gLogMutex;
|
|
|
|
static IO::FS::OpenWriteUnique_t gFileHandle;
|
2021-09-06 10:58:08 +00:00
|
|
|
|
|
|
|
static const auto & gLogConfig = gRuntimeConfig.console.fio;
|
|
|
|
|
|
|
|
static AuString GetLogDirectory()
|
|
|
|
{
|
|
|
|
AuString path;
|
|
|
|
AuString procName;
|
|
|
|
|
|
|
|
if (!IO::FS::GetProfileDomain(path))
|
|
|
|
{
|
|
|
|
path = ".";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Process::GetProcName(procName))
|
|
|
|
{
|
|
|
|
procName = "Unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
path += "/Logs/";
|
|
|
|
path += procName;
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
static void EraseFilesByTimestamp(const AuString &path, /*const its not worth reallocation*/ AuList<AuString> &files)
|
|
|
|
{
|
|
|
|
if (files.size() <= gLogConfig.maxLogs)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// our filenames are usually prefixed by an ISO 8601 timestamp where the most significant bits are last (YYYY-MM-DD?HH-MM-SS)
|
|
|
|
// a quick ghetto sort should be all we need. no need to waste time parsing timestamps
|
|
|
|
std::sort(files.begin(), files.end());
|
|
|
|
|
|
|
|
auto amount = files.size() - gLogConfig.maxLogs;
|
|
|
|
for (auto x = 0, i = 0; ((x < amount) && (i > files.size())); i++)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (IO::FS::Remove(path + "/" + files[i]))
|
|
|
|
{
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CleanupOldLogs()
|
|
|
|
{
|
|
|
|
AuList<AuString> files;
|
|
|
|
AuBST<AuString, IO::FS::Stat> fileMeta;
|
|
|
|
AuUInt32 size {};
|
2021-09-06 10:58:08 +00:00
|
|
|
|
|
|
|
auto baseLogPath = GetLogDirectory();
|
|
|
|
|
|
|
|
IO::FS::FilesInDirectory(baseLogPath, files);
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
for (const auto &file : files)
|
|
|
|
{
|
|
|
|
IO::FS::Stat stat;
|
2021-09-06 10:58:08 +00:00
|
|
|
IO::FS::StatFile(baseLogPath + "/" + file, stat);
|
2021-06-27 21:25:29 +00:00
|
|
|
fileMeta[file] = stat;
|
|
|
|
size += stat.size;
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
EraseFilesByTimestamp(baseLogPath, files);
|
2021-06-27 21:25:29 +00:00
|
|
|
// TODO: erase when size >= gLogConfig.maxSizeMb * 1024
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CompressLogs()
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
// TODO: write XZ's
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Flush()
|
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
/// It should be expected that the TLS teardown emergency flush to dispatch after deinit
|
|
|
|
if (!gLogMutex)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
AU_LOCK_GUARD(gLogMutex->AsReadable());
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
if (gFileHandle)
|
|
|
|
{
|
|
|
|
gFileHandle->Write(gLogBuffer.data(), gLogBuffer.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
gLogBuffer.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool OpenLogFile()
|
|
|
|
{
|
|
|
|
AuString path;
|
|
|
|
|
|
|
|
auto tm = Time::ToCivilTime(Time::CurrentClockMS());
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
path = fmt::format("{}/{:04}-{:02}-{:02}T{:02}-{:02}-{:02}Z.txt",
|
|
|
|
GetLogDirectory(),
|
|
|
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
|
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
gFileHandle = IO::FS::OpenWriteUnique(path);
|
2021-09-06 10:58:08 +00:00
|
|
|
return static_cast<bool>(gFileHandle);
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
void FIOCleanup()
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
|
|
|
CleanupOldLogs();
|
2021-09-06 10:58:08 +00:00
|
|
|
CompressLogs();
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Init()
|
|
|
|
{
|
|
|
|
if (!gLogConfig.enableLogging)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!OpenLogFile())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gLogMutex = Threading::Primitives::RWLockUnique();
|
|
|
|
if (!gLogMutex)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
Console::Hooks::AddFunctionalHook([&](const Console::ConsoleMessage &string) -> void
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2021-09-06 10:58:08 +00:00
|
|
|
AU_LOCK_GUARD(gLogMutex->AsWritable());
|
2021-06-27 21:25:29 +00:00
|
|
|
auto str = string.ToSimplified();
|
|
|
|
|
|
|
|
gLogBuffer.reserve(gLogBuffer.size() + str.size() + 2);
|
|
|
|
|
|
|
|
gLogBuffer.insert(gLogBuffer.end(), reinterpret_cast<AuUInt8*>(str.data()), reinterpret_cast<AuUInt8*>(str.data()) + str.size());
|
|
|
|
|
2021-09-06 10:58:08 +00:00
|
|
|
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
2021-06-27 21:25:29 +00:00
|
|
|
gLogBuffer.insert(gLogBuffer.end(), AuUInt8('\r'));
|
|
|
|
#endif
|
|
|
|
gLogBuffer.insert(gLogBuffer.end(), AuUInt8('\n'));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void Pump()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Exit()
|
|
|
|
{
|
|
|
|
Flush();
|
|
|
|
gLogMutex.reset();
|
|
|
|
gFileHandle.reset();
|
|
|
|
}
|
|
|
|
}
|