mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
Opening a zone the first time built its terrain, scene objects and manifests and ran ImageMagick on the web thread, stalling the dashboard for seconds. - Workers: the shared pool plus Workers::Reply (answer at once when built, else from a worker via Web::Defer). - terrain_chunks/terrain_layers/scene/paths/scenery/flairs (world3d, property and showcase routes) and terrain textures go through it; results are built once in OnceCaches, the .raw is read once per zone for chunks, layers and flairs, deflated bodies are cached thread-safely. - ImageMagick conversions are deduplicated and written under a temporary name. - Workers don't query the CDClient, read settings or call mongoose: ZoneTable, render components, flairs, object names, LOT kinds and terrain texture names are read at startup; client_location is read once; base64 is plain C++. - Logger writes one line at a time (mutex; localtime's buffer is shared). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
122 lines
3.1 KiB
C++
122 lines
3.1 KiB
C++
#include "Logger.h"
|
|
|
|
#include <algorithm>
|
|
#include <ctime>
|
|
#include <filesystem>
|
|
#include <mutex>
|
|
#include <stdarg.h>
|
|
|
|
namespace {
|
|
// Servers with worker threads (the dashboard) log from several threads: one line is written at a time, and
|
|
// localtime's buffer is shared
|
|
std::mutex g_LogMutex;
|
|
}
|
|
|
|
Writer::~Writer() {
|
|
// Flush before we close
|
|
Flush();
|
|
// Dont try to close stdcout...
|
|
if (!m_Outfile || m_IsConsoleWriter) return;
|
|
|
|
fclose(m_Outfile);
|
|
m_Outfile = NULL;
|
|
}
|
|
|
|
void Writer::Log(const char* time, const char* message) {
|
|
if (!m_Outfile || !m_Enabled) return;
|
|
|
|
fputs(time, m_Outfile);
|
|
fputs(message, m_Outfile);
|
|
}
|
|
|
|
void Writer::Flush() {
|
|
if (!m_Outfile) return;
|
|
fflush(m_Outfile);
|
|
}
|
|
|
|
FileWriter::FileWriter(const char* outpath) {
|
|
m_Outfile = fopen(outpath, "wt");
|
|
if (!m_Outfile) printf("Couldn't open %s for writing!\n", outpath);
|
|
m_Outpath = outpath;
|
|
m_IsConsoleWriter = false;
|
|
}
|
|
|
|
ConsoleWriter::ConsoleWriter(bool enabled) {
|
|
m_Enabled = enabled;
|
|
m_Outfile = stdout;
|
|
m_IsConsoleWriter = true;
|
|
}
|
|
|
|
Logger::Logger(const std::string& outpath, bool logToConsole, bool logDebugStatements) {
|
|
m_logDebugStatements = logDebugStatements;
|
|
std::filesystem::path outpathPath(outpath);
|
|
if (!std::filesystem::exists(outpathPath.parent_path())) std::filesystem::create_directories(outpathPath.parent_path());
|
|
m_Writers.push_back(std::make_unique<FileWriter>(outpath));
|
|
m_Writers.push_back(std::make_unique<ConsoleWriter>(logToConsole));
|
|
}
|
|
|
|
void Logger::vLog(const char* format, va_list args) {
|
|
std::lock_guard lock(g_LogMutex);
|
|
time_t t = time(NULL);
|
|
struct tm* time = localtime(&t);
|
|
char timeStr[70];
|
|
strftime(timeStr, sizeof(timeStr), "[%d-%m-%y %H:%M:%S ", time);
|
|
char message[2048];
|
|
vsnprintf(message, 2048, format, args);
|
|
for (const auto& writer : m_Writers) {
|
|
writer->Log(timeStr, message);
|
|
}
|
|
}
|
|
|
|
void Logger::Log(const char* className, const char* format, ...) {
|
|
va_list args;
|
|
std::string log = std::string(className) + "] " + std::string(format) + "\n";
|
|
va_start(args, format);
|
|
vLog(log.c_str(), args);
|
|
va_end(args);
|
|
}
|
|
|
|
void Logger::LogDebug(const char* className, const char* format, ...) {
|
|
if (!m_logDebugStatements) return;
|
|
va_list args;
|
|
std::string log = std::string(className) + "] " + std::string(format) + "\n";
|
|
va_start(args, format);
|
|
vLog(log.c_str(), args);
|
|
va_end(args);
|
|
}
|
|
|
|
void Logger::Flush() {
|
|
std::lock_guard lock(g_LogMutex);
|
|
for (const auto& writer : m_Writers) {
|
|
writer->Flush();
|
|
}
|
|
}
|
|
|
|
void Logger::SetLogToConsole(bool logToConsole) {
|
|
for (const auto& writer : m_Writers) {
|
|
if (writer->IsConsoleWriter()) writer->SetEnabled(logToConsole);
|
|
}
|
|
}
|
|
|
|
bool Logger::GetLogToConsole() const {
|
|
bool toReturn = false;
|
|
for (const auto& writer : m_Writers) {
|
|
if (writer->IsConsoleWriter()) toReturn |= writer->GetEnabled();
|
|
}
|
|
return toReturn;
|
|
}
|
|
|
|
FuncEntry::FuncEntry(const char* funcName, const char* fileName, const uint32_t line) {
|
|
m_FuncName = funcName;
|
|
if (!m_FuncName) m_FuncName = "Unknown";
|
|
m_Line = line;
|
|
m_FileName = fileName;
|
|
LOG("--> %s::%s:%i", m_FileName, m_FuncName, m_Line);
|
|
}
|
|
|
|
FuncEntry::~FuncEntry() {
|
|
if (!m_FuncName || !m_FileName) return;
|
|
|
|
LOG("<-- %s::%s:%i", m_FileName, m_FuncName, m_Line);
|
|
}
|