16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 00:49:19 +02:00
Files
maszyna/utilities/Logs.cpp
2026-05-19 19:04:46 +02:00

328 lines
7.2 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "utilities/Logs.h"
#include "utilities/Globals.h"
#include "winheaders.h"
#include "utilities/utilities.h"
#include "application/uilayer.h"
#include <deque>
std::ofstream output; // standardowy "log.txt", można go wyłączyć
std::ofstream errors; // lista błędów "errors.txt", zawsze działa
std::ofstream comms; // lista komunikatow "comms.txt", można go wyłączyć
char logbuffer[ 256 ];
char endstring[10] = "\n";
std::deque<std::string> log_scrollback;
namespace
{
std::string sanitize_filename_component(std::string value)
{
for (auto &character : value)
{
switch (character)
{
case '\\':
case '/':
case ':':
case '*':
case '?':
case '\"':
case '<':
case '>':
case '|':
character = '_';
break;
default:
break;
}
}
return value;
}
std::string filename_session_timestamp()
{
::SYSTEMTIME st {};
#ifdef __unix__
timespec ts {};
clock_gettime(CLOCK_REALTIME, &ts);
tm *tms = localtime(&ts.tv_sec);
if (tms != nullptr)
{
st.wYear = static_cast<unsigned short>(tms->tm_year + 1900);
st.wMonth = static_cast<unsigned short>(tms->tm_mon + 1);
st.wDay = static_cast<unsigned short>(tms->tm_mday);
st.wHour = static_cast<unsigned short>(tms->tm_hour);
st.wMinute = static_cast<unsigned short>(tms->tm_min);
st.wSecond = static_cast<unsigned short>(tms->tm_sec);
st.wMilliseconds = static_cast<unsigned short>(ts.tv_nsec / 1000000);
}
#elif _WIN32
::GetLocalTime(&st);
#endif
std::snprintf(
logbuffer,
sizeof(logbuffer),
"%04u%02u%02u_%02u%02u%02u_%03u",
static_cast<unsigned>(st.wYear),
static_cast<unsigned>(st.wMonth),
static_cast<unsigned>(st.wDay),
static_cast<unsigned>(st.wHour),
static_cast<unsigned>(st.wMinute),
static_cast<unsigned>(st.wSecond),
static_cast<unsigned>(st.wMilliseconds));
return std::string(logbuffer);
}
std::string const &log_session_id()
{
static std::string const session_id = []()
{
std::string session = filename_session_timestamp();
#ifdef _WIN32
char pid_suffix[32];
std::snprintf(pid_suffix, sizeof(pid_suffix), "_%lu", static_cast<unsigned long>(::GetCurrentProcessId()));
session += pid_suffix;
#endif
return session;
}();
return session_id;
}
std::string filename_scenery()
{
auto extension = Global.SceneryFile.rfind('.');
if (extension != std::string::npos)
{
return sanitize_filename_component(Global.SceneryFile.substr(0, extension));
}
return sanitize_filename_component(Global.SceneryFile);
}
std::string log_output_filename()
{
if (Global.MultipleLogs && false == Global.SceneryFile.empty())
{
return "logs/log (" + filename_scenery() + ") " + log_session_id() + ".txt";
}
return "logs/log_" + log_session_id() + ".txt";
}
std::string log_errors_filename()
{
if (Global.MultipleLogs && false == Global.SceneryFile.empty())
{
return "logs/errors (" + filename_scenery() + ") " + log_session_id() + ".txt";
}
return "logs/errors_" + log_session_id() + ".txt";
}
} // namespace
// log service stacks
std::deque < std::pair<std::string, bool>> InfoStack;
std::deque<std::string> ErrorStack;
// lock for log stacks
std::mutex logMutex;
void LogService()
{
// prevent crash if mutex is not initialized
while (true)
{
try
{
logMutex.lock();
break;
}
catch (...) {}
}
logMutex.unlock();
while (!Global.applicationQuitOrder)
{
{
// --- Obsługa InfoStack ---
while (!InfoStack.empty())
{
logMutex.lock();
std::string msg = InfoStack.front().first;
bool isError = InfoStack.front().second;
InfoStack.pop_front();
logMutex.unlock();
// log to file
if (Global.iWriteLogEnabled & 1)
{
if (!output.is_open())
{
output.open(log_output_filename(), std::ios::trunc);
}
output << msg << "\n";
output.flush();
}
// log to scrollback imgui
log_scrollback.emplace_back(msg);
if (log_scrollback.size() > 200)
log_scrollback.pop_front();
// log to console
if (Global.iWriteLogEnabled & 2)
{
if (isError)
printf("\033[1;37;41m%s\033[0m\n", msg.c_str());
else
printf("\033[32m%s\033[0m\n", msg.c_str());
}
}
// --- Obsługa ErrorStack ---
while (!ErrorStack.empty())
{
logMutex.lock();
std::string msg = ErrorStack.front();
ErrorStack.pop_front();
logMutex.unlock();
if (!(Global.iWriteLogEnabled & 1))
continue;
if (!errors.is_open())
{
errors.open(log_errors_filename(), std::ios::trunc);
errors << "EU07.EXE " + Global.asVersion << "\n";
}
errors << msg << "\n";
errors.flush();
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
bool ShouldSkipLog(std::string_view str, logtype type)
{
return str.empty() ||
TestFlag(Global.DisabledLogTypes, static_cast<unsigned int>(type));
}
std::string FormatLogMessage(std::string_view str)
{
const auto now = std::chrono::steady_clock::now();
const auto elapsed = now - Global.startTimestamp;
const double seconds = std::chrono::duration<double>(elapsed).count();
return std::format("[ {:8.3f} ]\t\t{}", seconds, str);
}
void WriteLog(std::string_view str, logtype type, bool isError)
{
if (ShouldSkipLog(str, type))
return;
const auto message = FormatLogMessage(str);
std::lock_guard<std::mutex> lock(logMutex);
InfoStack.push_back({message, isError});
}
void ErrorLog(std::string_view str, logtype type)
{
if (ShouldSkipLog(str, type))
return;
const auto message = FormatLogMessage(str);
std::lock_guard<std::mutex> lock(logMutex);
ErrorStack.push_back(message);
}
void WriteLog(const char* str, logtype type, bool isError)
{
if (str == nullptr || *str == '\0')
return;
WriteLog(std::string_view{str}, type, isError);
}
void ErrorLog(const char* str, logtype type)
{
if (str == nullptr || *str == '\0')
return;
ErrorLog(std::string_view{str}, type);
}
void Error(const std::string &asMessage, bool box)
{
// if (box)
// MessageBox(NULL, asMessage.c_str(), string("EU07 " + Global.asRelease).c_str(), MB_OK);
ErrorLog(asMessage.c_str());
}
void Error(const char *&asMessage, bool box)
{
// if (box)
// MessageBox(NULL, asMessage, string("EU07 " + Global.asRelease).c_str(), MB_OK);
ErrorLog(asMessage);
WriteLog(asMessage);
}
void ErrorLog(const std::string &str, logtype const Type )
{
ErrorLog( str.c_str(), Type );
WriteLog( str.c_str(), Type, true );
}
void WriteLog(const std::string &str, logtype const Type )
{ // Ra: wersja z AnsiString jest zamienna z Error()
WriteLog( str.c_str(), Type );
};
void CommLog(const char *str)
{ // Ra: warunkowa rejestracja komunikatów
WriteLog(str);
/* if (Global.iWriteLogEnabled & 4)
{
if (!comms.is_open())
{
comms.open("comms.txt", std::ios::trunc);
comms << AnsiString("EU07.EXE " + Global.asRelease).c_str() << "\n";
}
if (str)
comms << str;
comms << "\n";
comms.flush();
}*/
};
void CommLog(const std::string &str)
{ // Ra: wersja z AnsiString jest zamienna z Error()
WriteLog(str);
};
//---------------------------------------------------------------------------