diff --git a/src/common/Logging/AppenderConsole.cpp b/src/common/Logging/AppenderConsole.cpp index b5356b6f6..e7c63eadb 100644 --- a/src/common/Logging/AppenderConsole.cpp +++ b/src/common/Logging/AppenderConsole.cpp @@ -194,6 +194,8 @@ void AppenderConsole::_write(LogMessage const* message) case LOG_LEVEL_FATAL: index = 0; break; + case LOG_LEVEL_ERROR: + [[fallthrough]]; default: index = 1; break; diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp index 0c5874160..cb58d80dd 100644 --- a/src/common/Logging/Log.cpp +++ b/src/common/Logging/Log.cpp @@ -20,9 +20,11 @@ #include "AppenderFile.h" #include "Config.h" #include "Errors.h" +#include "IoContext.h" #include "LogMessage.h" #include "LogOperation.h" #include "Logger.h" +#include "Strand.h" #include "StringConvert.h" #include "Timer.h" #include "Tokenize.h" @@ -38,6 +40,7 @@ Log::Log() : AppenderId(0), highestLogLevel(LOG_LEVEL_FATAL) Log::~Log() { + delete _strand; Close(); } @@ -240,7 +243,13 @@ void Log::write(std::unique_ptr&& msg) const { Logger const* logger = GetLoggerByType(msg->type); - logger->write(msg.get()); + if (_ioContext) + { + std::shared_ptr logOperation = std::make_shared(logger, std::move(msg)); + Acore::Asio::post(*_ioContext, Acore::Asio::bind_executor(*_strand, [logOperation]() { logOperation->call(); })); + } + else + logger->write(msg.get()); } Logger const* Log::GetLoggerByType(std::string const& type) const @@ -356,11 +365,24 @@ Log* Log::instance() return &instance; } -void Log::Initialize() +void Log::Initialize(Acore::Asio::IoContext* ioContext) { + if (ioContext) + { + _ioContext = ioContext; + _strand = new Acore::Asio::Strand(*ioContext); + } + LoadFromConfig(); } +void Log::SetSynchronous() +{ + delete _strand; + _strand = nullptr; + _ioContext = nullptr; +} + void Log::LoadFromConfig() { Close(); diff --git a/src/common/Logging/Log.h b/src/common/Logging/Log.h index 717dc04b7..32ace618c 100644 --- a/src/common/Logging/Log.h +++ b/src/common/Logging/Log.h @@ -29,6 +29,12 @@ class Appender; class Logger; struct LogMessage; +namespace Acore::Asio +{ + class IoContext; + class Strand; +} + #define LOGGER_ROOT "root" typedef Appender*(*AppenderCreatorFn)(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector const& extraArgs); @@ -54,7 +60,8 @@ private: public: static Log* instance(); - void Initialize(); + void Initialize(Acore::Asio::IoContext* ioContext); + void SetSynchronous(); // Not threadsafe - should only be called from main() after all threads are joined void LoadFromConfig(); void Close(); [[nodiscard]] bool ShouldLog(std::string const& type, LogLevel level) const; @@ -112,6 +119,8 @@ private: std::string m_logsDir; std::string m_logsTimestamp; + Acore::Asio::IoContext* _ioContext; + Acore::Asio::Strand* _strand; // Deprecated debug filter logs DebugLogFilters _debugLogMask; }; diff --git a/src/common/Logging/LogCommon.h b/src/common/Logging/LogCommon.h index c0695a95d..56b6dc58c 100644 --- a/src/common/Logging/LogCommon.h +++ b/src/common/Logging/LogCommon.h @@ -23,13 +23,13 @@ // EnumUtils: DESCRIBE THIS enum LogLevel : uint8 { - LOG_LEVEL_DISABLED, - LOG_LEVEL_FATAL, - LOG_LEVEL_ERROR, - LOG_LEVEL_WARN, - LOG_LEVEL_INFO, - LOG_LEVEL_DEBUG, - LOG_LEVEL_TRACE, + LOG_LEVEL_DISABLED = 0, + LOG_LEVEL_FATAL = 1, + LOG_LEVEL_ERROR = 2, + LOG_LEVEL_WARN = 3, + LOG_LEVEL_INFO = 4, + LOG_LEVEL_DEBUG = 5, + LOG_LEVEL_TRACE = 6, NUM_ENABLED_LOG_LEVELS = LOG_LEVEL_TRACE, // SKIP LOG_LEVEL_INVALID = 0xFF // SKIP diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 0ddb139a9..a38e58b64 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -98,7 +98,7 @@ int main(int argc, char** argv) // Init logging sLog->RegisterAppender(); - sLog->Initialize(); + sLog->Initialize(nullptr); Acore::Banner::Show("authserver", [](std::string_view text) diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 4d2279633..f49740a36 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -199,7 +199,8 @@ int main(int argc, char** argv) // Init all logs sLog->RegisterAppender(); - sLog->Initialize(); + // If logs are supposed to be handled async then we need to pass the IoContext into the Log singleton + sLog->Initialize(sConfigMgr->GetOption("Log.Async.Enable", false) ? ioContext.get() : nullptr); Acore::Banner::Show("worldserver-daemon", [](std::string_view text) @@ -421,6 +422,8 @@ int main(int argc, char** argv) // Shutdown starts here threadPool.reset(); + sLog->SetSynchronous(); + sScriptMgr->OnShutdown(); // set server offline diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index a8cefe623..66e5b0636 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3914,6 +3914,16 @@ Logger.module=4,Console Server #Logger.vehicles=4,Console Server #Logger.warden=4,Console Server #Logger.weather=4,Console Server + +# +# Log.Async.Enable +# Description: Enables asynchronous message logging. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Log.Async.Enable = 0 + +# ################################################################################################### ###################################################################################################