#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Logger.h" #include "OSSupport/IsThread.h" #ifdef _WIN32 #include #endif static void WriteLogOpener(fmt::memory_buffer & Buffer) { time_t rawtime; time(&rawtime); struct tm * timeinfo; #ifdef _MSC_VER struct tm timeinforeal; timeinfo = &timeinforeal; localtime_s(timeinfo, &rawtime); #else timeinfo = localtime(&rawtime); #endif #ifdef _DEBUG const auto ThreadID = std::hash()(std::this_thread::get_id()); fmt::format_to( Buffer, "[{0:04x}|{1:02d}:{2:02d}:{3:02d}] ", ThreadID, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec ); #else fmt::format_to( Buffer, "[{0:02d}:{1:02d}:{2:02d}] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec ); #endif } cLogger & cLogger::GetInstance(void) { static cLogger Instance; return Instance; } void cLogger::InitiateMultithreading() { GetInstance(); } void cLogger::LogSimple(std::string_view a_Message, eLogLevel a_LogLevel) { fmt::memory_buffer Buffer; WriteLogOpener(Buffer); fmt::format_to(Buffer, "{0}\n", a_Message); LogLine(std::string_view(Buffer.data(), Buffer.size()), a_LogLevel); } void cLogger::LogLine(std::string_view a_Line, eLogLevel a_LogLevel) { cCSLock Lock(m_CriticalSection); for (size_t i = 0; i < m_LogListeners.size(); i++) { m_LogListeners[i]->Log(a_Line, a_LogLevel); } } void cLogger::LogPrintf( std::string_view a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList ) { fmt::memory_buffer Buffer; WriteLogOpener(Buffer); fmt::printf(Buffer, fmt::to_string_view(a_Format), a_ArgList); fmt::format_to(Buffer, "\n"); LogLine(std::string_view(Buffer.data(), Buffer.size()), a_LogLevel); } void cLogger::LogFormat( std::string_view a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList ) { fmt::memory_buffer Buffer; WriteLogOpener(Buffer); fmt::vformat_to(Buffer, a_Format, a_ArgList); fmt::format_to(Buffer, "\n"); LogLine(std::string_view(Buffer.data(), Buffer.size()), a_LogLevel); } cLogger::cAttachment cLogger::AttachListener(std::unique_ptr a_Listener) { auto nonOwning = a_Listener.get(); { cCSLock Lock(m_CriticalSection); m_LogListeners.push_back(std::move(a_Listener)); } return cAttachment{nonOwning}; } void cLogger::DetachListener(cListener * a_Listener) { cCSLock Lock(m_CriticalSection); m_LogListeners.erase( std::remove_if( m_LogListeners.begin(), m_LogListeners.end(), [=](std::unique_ptr & a_OtherListener) -> bool { return a_OtherListener.get() == a_Listener; } ) ); } //////////////////////////////////////////////////////////////////////////////// // Global functions void Logger::LogFormat( std::string_view a_Format, eLogLevel a_LogLevel, fmt::format_args a_ArgList ) { cLogger::GetInstance().LogFormat(a_Format, a_LogLevel, a_ArgList); } void Logger::LogPrintf( std::string_view a_Format, eLogLevel a_LogLevel, fmt::printf_args a_ArgList ) { cLogger::GetInstance().LogPrintf(a_Format, a_LogLevel, a_ArgList); } void Logger::LogSimple(std::string_view a_Message, eLogLevel a_LogLevel) { cLogger::GetInstance().LogSimple(a_Message, a_LogLevel); }