AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Log Class Reference

#include "Log.h"

Public Member Functions

void Initialize (Acore::Asio::IoContext *ioContext=nullptr)
 
void SetSynchronous ()
 
void LoadFromConfig ()
 
void Close ()
 
bool ShouldLog (std::string const &type, LogLevel level) const
 
bool SetLogLevel (std::string const &name, int32 level, bool isLogger=true)
 
template<typename... Args>
void outMessage (std::string const &filter, LogLevel const level, std::string_view fmt, Args &&... args)
 
template<typename... Args>
void outCommand (uint32 account, std::string_view fmt, Args &&... args)
 
void SetRealmId (uint32 id)
 
template<class AppenderImpl >
void RegisterAppender ()
 
std::string const & GetLogsDir () const
 
std::string const & GetLogsTimestamp () const
 

Static Public Member Functions

static Loginstance ()
 

Private Types

typedef std::unordered_map< std::string, LoggerLoggerMap
 

Private Member Functions

 Log ()
 
 ~Log ()
 
 Log (Log const &)=delete
 
 Log (Log &&)=delete
 
Logoperator= (Log const &)=delete
 
Logoperator= (Log &&)=delete
 
void write (std::unique_ptr< LogMessage > &&msg) const
 
Logger const * GetLoggerByType (std::string const &type) const
 
AppenderGetAppenderByName (std::string_view name)
 
uint8 NextAppenderId ()
 
void CreateAppenderFromConfig (std::string const &name)
 
void CreateLoggerFromConfig (std::string const &name)
 
void ReadAppendersFromConfig ()
 
void ReadLoggersFromConfig ()
 
void RegisterAppender (uint8 index, AppenderCreatorFn appenderCreateFn)
 
void _outMessage (std::string const &filter, LogLevel level, std::string_view message)
 
void _outCommand (std::string_view message, std::string_view param1)
 

Static Private Member Functions

static std::string GetTimestampStr ()
 

Private Attributes

std::unordered_map< uint8, AppenderCreatorFnappenderFactory
 
std::unordered_map< uint8, std::unique_ptr< Appender > > appenders
 
std::unordered_map< std::string, std::unique_ptr< Logger > > loggers
 
uint8 AppenderId
 
LogLevel highestLogLevel
 
std::string m_logsDir
 
std::string m_logsTimestamp
 
Acore::Asio::IoContext_ioContext
 
Acore::Asio::Strand_strand
 
DebugLogFilters _debugLogMask
 

Detailed Description

Member Typedef Documentation

◆ LoggerMap

typedef std::unordered_map<std::string, Logger> Log::LoggerMap
private

Constructor & Destructor Documentation

◆ Log() [1/3]

Log::Log ( )
private
35{
37 RegisterAppender<AppenderConsole>();
38 RegisterAppender<AppenderFile>();
39}
@ LOG_LEVEL_FATAL
Definition: LogCommon.h:27
std::string m_logsTimestamp
Definition: Log.h:120
uint8 AppenderId
Definition: Log.h:116
static std::string GetTimestampStr()
Definition: Log.cpp:278
LogLevel highestLogLevel
Definition: Log.h:117

References GetTimestampStr(), and m_logsTimestamp.

◆ ~Log()

Log::~Log ( )
private
42{
43 delete _strand;
44 Close();
45}
Acore::Asio::Strand * _strand
Definition: Log.h:123
void Close()
Definition: Log.cpp:334

References _strand, and Close().

◆ Log() [2/3]

Log::Log ( Log const &  )
privatedelete

◆ Log() [3/3]

Log::Log ( Log &&  )
privatedelete

Member Function Documentation

◆ _outCommand()

void Log::_outCommand ( std::string_view  message,
std::string_view  param1 
)
private
238{
239 write(std::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm", message, param1));
240}
@ LOG_LEVEL_INFO
Definition: LogCommon.h:30
void write(std::unique_ptr< LogMessage > &&msg) const
Definition: Log.cpp:242

References LOG_LEVEL_INFO, and write().

Referenced by outCommand().

◆ _outMessage()

void Log::_outMessage ( std::string const &  filter,
LogLevel  level,
std::string_view  message 
)
private
233{
234 write(std::make_unique<LogMessage>(level, filter, message));
235}

References write().

Referenced by outMessage().

◆ Close()

void Log::Close ( )
335{
336 loggers.clear();
337 appenders.clear();
338}
std::unordered_map< uint8, std::unique_ptr< Appender > > appenders
Definition: Log.h:114
std::unordered_map< std::string, std::unique_ptr< Logger > > loggers
Definition: Log.h:115

References appenders, and loggers.

Referenced by LoadFromConfig(), ReadLoggersFromConfig(), and ~Log().

◆ CreateAppenderFromConfig()

void Log::CreateAppenderFromConfig ( std::string const &  name)
private
64{
65 if (appenderName.empty())
66 {
67 return;
68 }
69
70 // Format = type, level, flags, optional1, optional2
71 // if type = File. optional1 = file and option2 = mode
72 // if type = Console. optional1 = Color
73 std::string options = sConfigMgr->GetOption<std::string>(appenderName, "");
74
75 std::vector<std::string_view> tokens = Acore::Tokenize(options, ',', true);
76
77 size_t const size = tokens.size();
78 std::string name = appenderName.substr(9);
79
80 if (size < 2)
81 {
82 fmt::print(stderr, "Log::CreateAppenderFromConfig: Wrong configuration for appender {}. Config line: {}\n", name, options);
83 return;
84 }
85
87 AppenderType type = AppenderType(Acore::StringTo<uint8>(tokens[0]).value_or(APPENDER_INVALID));
88 LogLevel level = LogLevel(Acore::StringTo<uint8>(tokens[1]).value_or(LOG_LEVEL_INVALID));
89
90 auto factoryFunction = appenderFactory.find(type);
91 if (factoryFunction == appenderFactory.end())
92 {
93 fmt::print(stderr, "Log::CreateAppenderFromConfig: Unknown type '{}' for appender {}\n", tokens[0], name);
94 return;
95 }
96
97 if (level > NUM_ENABLED_LOG_LEVELS)
98 {
99 fmt::print(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level '{}' for appender {}\n", tokens[1], name);
100 return;
101 }
102
103 if (size > 2)
104 {
105 if (Optional<uint8> flagsVal = Acore::StringTo<uint8>(tokens[2]))
106 {
107 flags = AppenderFlags(*flagsVal);
108 }
109 else
110 {
111 fmt::print(stderr, "Log::CreateAppenderFromConfig: Unknown flags '{}' for appender {}\n", tokens[2], name);
112 return;
113 }
114 }
115
116 try
117 {
118 Appender* appender = factoryFunction->second(NextAppenderId(), name, level, flags, tokens);
119 appenders[appender->getId()].reset(appender);
120 }
121 catch (InvalidAppenderArgsException const& iaae)
122 {
123 fmt::print(stderr, "{}\n", iaae.what());
124 }
125}
#define sConfigMgr
Definition: Config.h:92
AppenderFlags
Definition: LogCommon.h:50
@ APPENDER_FLAGS_NONE
Definition: LogCommon.h:51
AppenderType
Definition: LogCommon.h:40
@ APPENDER_INVALID
Definition: LogCommon.h:46
LogLevel
Definition: LogCommon.h:25
@ NUM_ENABLED_LOG_LEVELS
Definition: LogCommon.h:34
@ LOG_LEVEL_INVALID
Definition: LogCommon.h:35
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:24
std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Tokenize.cpp:20
Definition: Appender.h:30
uint8 getId() const
Definition: Appender.cpp:28
Definition: Appender.h:56
uint8 NextAppenderId()
Definition: Log.cpp:47
std::unordered_map< uint8, AppenderCreatorFn > appenderFactory
Definition: Log.h:113

References APPENDER_FLAGS_NONE, APPENDER_INVALID, appenderFactory, appenders, Appender::getId(), LOG_LEVEL_INVALID, NextAppenderId(), NUM_ENABLED_LOG_LEVELS, sConfigMgr, and Acore::Tokenize().

Referenced by ReadAppendersFromConfig().

◆ CreateLoggerFromConfig()

void Log::CreateLoggerFromConfig ( std::string const &  name)
private
128{
129 if (appenderName.empty())
130 {
131 return;
132 }
133
135
136 std::string options = sConfigMgr->GetOption<std::string>(appenderName, "");
137 std::string name = appenderName.substr(7);
138
139 if (options.empty())
140 {
141 fmt::print(stderr, "Log::CreateLoggerFromConfig: Missing config option Logger.{}\n", name);
142 return;
143 }
144
145 std::vector<std::string_view> tokens = Acore::Tokenize(options, ',', true);
146
147 if (tokens.size() != 2)
148 {
149 fmt::print(stderr, "Log::CreateLoggerFromConfig: Wrong config option Logger.%s=%s\n", name, options);
150 return;
151 }
152
153 std::unique_ptr<Logger>& logger = loggers[name];
154 if (logger)
155 {
156 fmt::print(stderr, "Error while configuring Logger {}. Already defined\n", name);
157 return;
158 }
159
160 level = LogLevel(Acore::StringTo<uint8>(tokens[0]).value_or(LOG_LEVEL_INVALID));
161 if (level > NUM_ENABLED_LOG_LEVELS)
162 {
163 fmt::print(stderr, "Log::CreateLoggerFromConfig: Wrong Log Level '{}' for logger {}\n", tokens[0], name);
164 return;
165 }
166
167 if (level > highestLogLevel)
168 {
169 highestLogLevel = level;
170 }
171
172 logger = std::make_unique<Logger>(name, level);
173
174 for (std::string_view appendName : Acore::Tokenize(tokens[1], ' ', false))
175 {
176 if (Appender* appender = GetAppenderByName(appendName))
177 {
178 logger->addAppender(appender->getId(), appender);
179 }
180 else
181 {
182 fmt::print(stderr, "Error while configuring Appender {} in Logger {}. Appender does not exist\n", appendName, name);
183 }
184 }
185}
@ LOG_LEVEL_DISABLED
Definition: LogCommon.h:26
Appender * GetAppenderByName(std::string_view name)
Definition: Log.cpp:52

References GetAppenderByName(), highestLogLevel, LOG_LEVEL_DISABLED, LOG_LEVEL_INVALID, loggers, NUM_ENABLED_LOG_LEVELS, sConfigMgr, and Acore::Tokenize().

Referenced by ReadLoggersFromConfig().

◆ GetAppenderByName()

Appender * Log::GetAppenderByName ( std::string_view  name)
private
53{
54 auto it = appenders.begin();
55 while (it != appenders.end() && it->second && it->second->getName() != name)
56 {
57 ++it;
58 }
59
60 return it == appenders.end() ? nullptr : it->second.get();
61}

References appenders.

Referenced by CreateLoggerFromConfig(), and SetLogLevel().

◆ GetLoggerByType()

Logger const * Log::GetLoggerByType ( std::string const &  type) const
private
256{
257 auto it = loggers.find(type);
258 if (it != loggers.end())
259 {
260 return it->second.get();
261 }
262
263 if (type == LOGGER_ROOT)
264 {
265 return nullptr;
266 }
267
268 std::string parentLogger = LOGGER_ROOT;
269 size_t found = type.find_last_of('.');
270 if (found != std::string::npos)
271 {
272 parentLogger = type.substr(0, found);
273 }
274
275 return GetLoggerByType(parentLogger);
276}
#define LOGGER_ROOT
Definition: Log.h:38
Logger const * GetLoggerByType(std::string const &type) const
Definition: Log.cpp:255

References GetLoggerByType(), LOGGER_ROOT, and loggers.

Referenced by GetLoggerByType(), ShouldLog(), and write().

◆ GetLogsDir()

std::string const & Log::GetLogsDir ( ) const
inline
95{ return m_logsDir; }
std::string m_logsDir
Definition: Log.h:119

References m_logsDir.

◆ GetLogsTimestamp()

std::string const & Log::GetLogsTimestamp ( ) const
inline
96{ return m_logsTimestamp; }

References m_logsTimestamp.

◆ GetTimestampStr()

std::string Log::GetTimestampStr ( )
staticprivate
279{
280 return Acore::Time::TimeToTimestampStr(GetEpochTime(), "%Y-%m-%d_%H_%M_%S");
281}
Seconds GetEpochTime()
Definition: Timer.h:141
AC_COMMON_API std::string TimeToTimestampStr(Seconds time=0s, std::string_view fmt={})
Definition: Timer.cpp:272

References GetEpochTime(), and Acore::Time::TimeToTimestampStr().

Referenced by Log().

◆ Initialize()

void Log::Initialize ( Acore::Asio::IoContext ioContext = nullptr)
369{
370 if (ioContext)
371 {
372 _ioContext = ioContext;
373 _strand = new Acore::Asio::Strand(*ioContext);
374 }
375
377}
Definition: Strand.h:34
void LoadFromConfig()
Definition: Log.cpp:386
Acore::Asio::IoContext * _ioContext
Definition: Log.h:122

References _ioContext, _strand, and LoadFromConfig().

◆ instance()

Log * Log::instance ( )
static
363{
364 static Log instance;
365 return &instance;
366}
Definition: Log.h:49
static Log * instance()
Definition: Log.cpp:362

References instance().

Referenced by instance().

◆ LoadFromConfig()

void Log::LoadFromConfig ( )
387{
388 Close();
389
391 AppenderId = 0;
392 m_logsDir = sConfigMgr->GetOption<std::string>("LogsDir", "", false);
393
394 if (!m_logsDir.empty())
395 if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
396 {
397 m_logsDir.push_back('/');
398 }
399
402
403 _debugLogMask = DebugLogFilters(sConfigMgr->GetOption<uint32>("DebugLogMask", LOG_FILTER_NONE, false));
404}
std::uint32_t uint32
Definition: Define.h:108
DebugLogFilters
Definition: LogCommon.h:61
@ LOG_FILTER_NONE
Definition: LogCommon.h:62
DebugLogFilters _debugLogMask
Definition: Log.h:125
void ReadAppendersFromConfig()
Definition: Log.cpp:187
void ReadLoggersFromConfig()
Definition: Log.cpp:196

References _debugLogMask, AppenderId, Close(), highestLogLevel, LOG_FILTER_NONE, LOG_LEVEL_FATAL, m_logsDir, ReadAppendersFromConfig(), ReadLoggersFromConfig(), and sConfigMgr.

Referenced by Initialize().

◆ NextAppenderId()

uint8 Log::NextAppenderId ( )
private
48{
49 return AppenderId++;
50}

References AppenderId.

Referenced by CreateAppenderFromConfig(), and ReadLoggersFromConfig().

◆ operator=() [1/2]

Log & Log::operator= ( Log &&  )
privatedelete

◆ operator=() [2/2]

Log & Log::operator= ( Log const &  )
privatedelete

◆ outCommand()

template<typename... Args>
void Log::outCommand ( uint32  account,
std::string_view  fmt,
Args &&...  args 
)
inline
78 {
79 if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
80 {
81 return;
82 }
83
84 _outCommand(Acore::StringFormatFmt(fmt, std::forward<Args>(args)...), std::to_string(account));
85 }
std::string StringFormatFmt(std::string_view fmt, Args &&... args)
Definition: StringFormat.h:44
bool ShouldLog(std::string const &type, LogLevel level) const
Definition: Log.cpp:340
void _outCommand(std::string_view message, std::string_view param1)
Definition: Log.cpp:237

References _outCommand(), LOG_LEVEL_INFO, ShouldLog(), and Acore::StringFormatFmt().

◆ outMessage()

template<typename... Args>
void Log::outMessage ( std::string const &  filter,
LogLevel const  level,
std::string_view  fmt,
Args &&...  args 
)
inline
72 {
73 _outMessage(filter, level, Acore::StringFormatFmt(fmt, std::forward<Args>(args)...));
74 }
void _outMessage(std::string const &filter, LogLevel level, std::string_view message)
Definition: Log.cpp:232

References _outMessage(), and Acore::StringFormatFmt().

◆ ReadAppendersFromConfig()

void Log::ReadAppendersFromConfig ( )
private
188{
189 std::vector<std::string> keys = sConfigMgr->GetKeysByString("Appender.");
190 for (std::string const& appenderName : keys)
191 {
192 CreateAppenderFromConfig(appenderName);
193 }
194}
void CreateAppenderFromConfig(std::string const &name)
Definition: Log.cpp:63

References CreateAppenderFromConfig(), and sConfigMgr.

Referenced by LoadFromConfig().

◆ ReadLoggersFromConfig()

void Log::ReadLoggersFromConfig ( )
private
197{
198 std::vector<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
199 for (std::string const& loggerName : keys)
200 {
201 CreateLoggerFromConfig(loggerName);
202 }
203
204 // Bad config configuration, creating default config
205 if (loggers.find(LOGGER_ROOT) == loggers.end())
206 {
207 fmt::print(stderr, "Wrong Loggers configuration. Review your Logger config section.\n"
208 "Creating default loggers [root (Error), server (Info)] to console\n");
209
210 Close(); // Clean any Logger or Appender created
211
213 appenders[appender->getId()].reset(appender);
214
215 Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR);
216 rootLogger->addAppender(appender->getId(), appender);
217 loggers[LOGGER_ROOT].reset(rootLogger);
218
219 Logger* serverLogger = new Logger("server", LOG_LEVEL_INFO);
220 serverLogger->addAppender(appender->getId(), appender);
221 loggers["server"].reset(serverLogger);
222 }
223}
@ LOG_LEVEL_DEBUG
Definition: LogCommon.h:31
@ LOG_LEVEL_ERROR
Definition: LogCommon.h:28
Definition: AppenderConsole.h:45
void CreateLoggerFromConfig(std::string const &name)
Definition: Log.cpp:127
Definition: Logger.h:30
void addAppender(uint8 type, Appender *appender)
Definition: Logger.cpp:34

References Logger::addAppender(), APPENDER_FLAGS_NONE, appenders, Close(), CreateLoggerFromConfig(), Appender::getId(), LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOGGER_ROOT, loggers, NextAppenderId(), and sConfigMgr.

Referenced by LoadFromConfig().

◆ RegisterAppender() [1/2]

template<class AppenderImpl >
void Log::RegisterAppender ( )
inline
91 {
92 RegisterAppender(AppenderImpl::type, &CreateAppender<AppenderImpl>);
93 }
void RegisterAppender()
Definition: Log.h:90

References RegisterAppender().

Referenced by RegisterAppender().

◆ RegisterAppender() [2/2]

void Log::RegisterAppender ( uint8  index,
AppenderCreatorFn  appenderCreateFn 
)
private
226{
227 auto itr = appenderFactory.find(index);
228 ASSERT(itr == appenderFactory.end());
229 appenderFactory[index] = appenderCreateFn;
230}
#define ASSERT
Definition: Errors.h:68

References appenderFactory, and ASSERT.

◆ SetLogLevel()

bool Log::SetLogLevel ( std::string const &  name,
int32  level,
bool  isLogger = true 
)
284{
285 if (newLeveli < 0)
286 {
287 return false;
288 }
289
290 LogLevel newLevel = LogLevel(newLeveli);
291
292 if (isLogger)
293 {
294 auto it = loggers.begin();
295 while (it != loggers.end() && it->second->getName() != name)
296 {
297 ++it;
298 }
299
300 if (it == loggers.end())
301 {
302 return false;
303 }
304
305 it->second->setLogLevel(newLevel);
306
307 if (newLevel != LOG_LEVEL_DISABLED && newLevel > highestLogLevel)
308 {
309 highestLogLevel = newLevel;
310 }
311 }
312 else
313 {
314 Appender* appender = GetAppenderByName(name);
315 if (!appender)
316 {
317 return false;
318 }
319
320 appender->setLogLevel(newLevel);
321 }
322
323 return true;
324}
void setLogLevel(LogLevel)
Definition: Appender.cpp:48

References GetAppenderByName(), highestLogLevel, LOG_LEVEL_DISABLED, loggers, and Appender::setLogLevel().

◆ SetRealmId()

void Log::SetRealmId ( uint32  id)
327{
328 for (std::pair<uint8 const, std::unique_ptr<Appender>>& appender : appenders)
329 {
330 appender.second->setRealmId(id);
331 }
332}
std::uint8_t uint8
Definition: Define.h:110

References appenders.

◆ SetSynchronous()

void Log::SetSynchronous ( )
380{
381 delete _strand;
382 _strand = nullptr;
383 _ioContext = nullptr;
384}

References _ioContext, and _strand.

◆ ShouldLog()

bool Log::ShouldLog ( std::string const &  type,
LogLevel  level 
) const
Todo:
: Use cache to store "Type.sub1.sub2": "Type" equivalence, should
341{
343 // Speed up in cases where requesting "Type.sub1.sub2" but only configured
344 // Logger "Type"
345
346 // Don't even look for a logger if the LogLevel is higher than the highest log levels across all loggers
347 if (level > highestLogLevel)
348 {
349 return false;
350 }
351
352 Logger const* logger = GetLoggerByType(type);
353 if (!logger)
354 {
355 return false;
356 }
357
358 LogLevel logLevel = logger->getLogLevel();
359 return logLevel != LOG_LEVEL_DISABLED && logLevel >= level;
360}
LogLevel getLogLevel() const
Definition: Logger.cpp:29

References GetLoggerByType(), Logger::getLogLevel(), highestLogLevel, and LOG_LEVEL_DISABLED.

Referenced by outCommand().

◆ write()

void Log::write ( std::unique_ptr< LogMessage > &&  msg) const
private
243{
244 Logger const* logger = GetLoggerByType(msg->type);
245
246 if (_ioContext)
247 {
248 std::shared_ptr<LogOperation> logOperation = std::make_shared<LogOperation>(logger, std::move(msg));
249 Acore::Asio::post(*_ioContext, Acore::Asio::bind_executor(*_strand, [logOperation]() { logOperation->call(); }));
250 }
251 else
252 logger->write(msg.get());
253}
decltype(auto) bind_executor(Strand &strand, T &&t)
Definition: Strand.h:43
decltype(auto) post(IoContextBaseNamespace::IoContextBase &ioContext, T &&t)
Definition: IoContext.h:57
void write(LogMessage *message) const
Definition: Logger.cpp:49

References _ioContext, _strand, Acore::Asio::bind_executor(), GetLoggerByType(), Acore::Asio::post(), and Logger::write().

Referenced by _outCommand(), and _outMessage().

Member Data Documentation

◆ _debugLogMask

DebugLogFilters Log::_debugLogMask
private

Referenced by LoadFromConfig().

◆ _ioContext

Acore::Asio::IoContext* Log::_ioContext
private

Referenced by Initialize(), SetSynchronous(), and write().

◆ _strand

Acore::Asio::Strand* Log::_strand
private

◆ appenderFactory

std::unordered_map<uint8, AppenderCreatorFn> Log::appenderFactory
private

◆ AppenderId

uint8 Log::AppenderId
private

Referenced by LoadFromConfig(), and NextAppenderId().

◆ appenders

std::unordered_map<uint8, std::unique_ptr<Appender> > Log::appenders
private

◆ highestLogLevel

LogLevel Log::highestLogLevel
private

◆ loggers

std::unordered_map<std::string, std::unique_ptr<Logger> > Log::loggers
private

◆ m_logsDir

std::string Log::m_logsDir
private

Referenced by GetLogsDir(), and LoadFromConfig().

◆ m_logsTimestamp

std::string Log::m_logsTimestamp
private

Referenced by GetLogsTimestamp(), and Log().