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, Acore::FormatString< Args... > fmt, Args &&... args)
 
template<typename... Args>
void outCommand (uint32 account, Acore::FormatString< Args... > 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
 
std::unique_ptr< Acore::Asio::Strand_strand
 

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:121
uint8 AppenderId
Definition Log.h:117
static std::string GetTimestampStr()
Definition Log.cpp:280
LogLevel highestLogLevel
Definition Log.h:118

References GetTimestampStr(), and m_logsTimestamp.

◆ ~Log()

Log::~Log ( )
private
42{
43 Close();
44}
void Close()
Definition Log.cpp:336

References 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
240{
241 write(std::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm", message, param1));
242}
@ LOG_LEVEL_INFO
Definition LogCommon.h:30
void write(std::unique_ptr< LogMessage > &&msg) const
Definition Log.cpp:244

References LOG_LEVEL_INFO, and write().

Referenced by outCommand().

◆ _outMessage()

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

References write().

Referenced by outMessage().

◆ Close()

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

References appenders, and loggers.

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

◆ CreateAppenderFromConfig()

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

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

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
52{
53 auto it = appenders.begin();
54 while (it != appenders.end() && it->second && it->second->getName() != name)
55 {
56 ++it;
57 }
58
59 return it == appenders.end() ? nullptr : it->second.get();
60}

References appenders.

Referenced by CreateLoggerFromConfig(), and SetLogLevel().

◆ GetLoggerByType()

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

References GetLoggerByType(), LOGGER_ROOT, and loggers.

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

◆ GetLogsDir()

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

References m_logsDir.

◆ GetLogsTimestamp()

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

References m_logsTimestamp.

◆ GetTimestampStr()

std::string Log::GetTimestampStr ( )
staticprivate
281{
282 return Acore::Time::TimeToTimestampStr(GetEpochTime(), "%Y-%m-%d_%H_%M_%S");
283}
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)
371{
372 if (ioContext)
373 {
374 _ioContext = ioContext;
375 _strand = std::make_unique<Acore::Asio::Strand>(*ioContext);
376 }
377
379}
void LoadFromConfig()
Definition Log.cpp:387
std::unique_ptr< Acore::Asio::Strand > _strand
Definition Log.h:124
Acore::Asio::IoContext * _ioContext
Definition Log.h:123

References _ioContext, _strand, and LoadFromConfig().

◆ instance()

Log * Log::instance ( )
static
365{
366 static Log instance;
367 return &instance;
368}
Definition Log.h:50
static Log * instance()
Definition Log.cpp:364

References instance().

Referenced by instance().

◆ LoadFromConfig()

void Log::LoadFromConfig ( )
388{
389 Close();
390
392 AppenderId = 0;
393 m_logsDir = sConfigMgr->GetOption<std::string>("LogsDir", "", false);
394
395 if (!m_logsDir.empty())
396 if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
397 {
398 m_logsDir.push_back('/');
399 }
400
403}
void ReadAppendersFromConfig()
Definition Log.cpp:186
void ReadLoggersFromConfig()
Definition Log.cpp:195

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

Referenced by Initialize().

◆ NextAppenderId()

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

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,
Acore::FormatString< Args... >  fmt,
Args &&...  args 
)
inline
79 {
80 if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
81 {
82 return;
83 }
84
85 _outCommand(Acore::StringFormat(fmt, std::forward<Args>(args)...), std::to_string(account));
86 }
bool ShouldLog(std::string const &type, LogLevel level) const
Definition Log.cpp:342
void _outCommand(std::string_view message, std::string_view param1)
Definition Log.cpp:239
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default AC string format function.
Definition StringFormat.h:34

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

◆ outMessage()

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

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

◆ ReadAppendersFromConfig()

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

References CreateAppenderFromConfig(), and sConfigMgr.

Referenced by LoadFromConfig().

◆ ReadLoggersFromConfig()

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

Referenced by LoadFromConfig().

◆ RegisterAppender() [1/2]

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

References RegisterAppender().

Referenced by RegisterAppender().

◆ RegisterAppender() [2/2]

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

References appenderFactory, and ASSERT.

◆ SetLogLevel()

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

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

◆ SetRealmId()

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

References appenders.

◆ SetSynchronous()

void Log::SetSynchronous ( )
382{
383 _strand.reset();
384 _ioContext = nullptr;
385}

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
343{
345 // Speed up in cases where requesting "Type.sub1.sub2" but only configured
346 // Logger "Type"
347
348 // Don't even look for a logger if the LogLevel is higher than the highest log levels across all loggers
349 if (level > highestLogLevel)
350 {
351 return false;
352 }
353
354 Logger const* logger = GetLoggerByType(type);
355 if (!logger)
356 {
357 return false;
358 }
359
360 LogLevel logLevel = logger->getLogLevel();
361 return logLevel != LOG_LEVEL_DISABLED && logLevel >= level;
362}
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
245{
246 Logger const* logger = GetLoggerByType(msg->type);
247
248 if (_ioContext)
249 {
250 std::shared_ptr<LogOperation> logOperation = std::make_shared<LogOperation>(logger, std::move(msg));
251 Acore::Asio::post(*_ioContext, Acore::Asio::bind_executor(*_strand, [logOperation]() { logOperation->call(); }));
252 }
253 else
254 logger->write(msg.get());
255}
void write(LogMessage *message) const
Definition Logger.cpp:49
decltype(auto) post(IoContextBaseNamespace::IoContextBase &ioContext, T &&t)
Definition IoContext.h:48

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

Referenced by _outCommand(), and _outMessage().

Member Data Documentation

◆ _ioContext

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

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

◆ _strand

std::unique_ptr<Acore::Asio::Strand> Log::_strand
private

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

◆ 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

◆ 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().


The documentation for this class was generated from the following files: