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
 
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
34{
36 RegisterAppender<AppenderConsole>();
37 RegisterAppender<AppenderFile>();
38}
@ 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:277
LogLevel highestLogLevel
Definition: Log.h:117

References GetTimestampStr(), and m_logsTimestamp.

◆ ~Log()

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

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

References LOG_LEVEL_INFO, and write().

Referenced by outCommand().

◆ _outMessage()

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

References write().

Referenced by outMessage().

◆ Close()

void Log::Close ( )
334{
335 loggers.clear();
336 appenders.clear();
337}
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
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 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}
#define sConfigMgr
Definition: Config.h:95
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
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:46
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
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

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

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
278{
279 return Acore::Time::TimeToTimestampStr(GetEpochTime(), "%Y-%m-%d_%H_%M_%S");
280}
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)
368{
369 if (ioContext)
370 {
371 _ioContext = ioContext;
372 _strand = new Acore::Asio::Strand(*ioContext);
373 }
374
376}
Definition: Strand.h:34
void LoadFromConfig()
Definition: Log.cpp:385
Acore::Asio::IoContext * _ioContext
Definition: Log.h:122

References _ioContext, _strand, and LoadFromConfig().

◆ instance()

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

References instance().

Referenced by instance().

◆ LoadFromConfig()

void Log::LoadFromConfig ( )
386{
387 Close();
388
390 AppenderId = 0;
391 m_logsDir = sConfigMgr->GetOption<std::string>("LogsDir", "", false);
392
393 if (!m_logsDir.empty())
394 if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
395 {
396 m_logsDir.push_back('/');
397 }
398
401}
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
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(FormatString< Args... > fmt, Args &&... args)
Definition: StringFormat.h:48
bool ShouldLog(std::string const &type, LogLevel level) const
Definition: Log.cpp:339
void _outCommand(std::string_view message, std::string_view param1)
Definition: Log.cpp:236

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

◆ outMessage()

template<typename... Args>
void Log::outMessage ( std::string const &  filter,
LogLevel const  level,
Acore::FormatString< Args... >  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:231

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

◆ 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_ERROR);
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 }
222}
@ 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: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(), 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
225{
226 auto itr = appenderFactory.find(index);
227 ASSERT(itr == appenderFactory.end());
228 appenderFactory[index] = appenderCreateFn;
229}
#define ASSERT
Definition: Errors.h:68

References appenderFactory, and ASSERT.

◆ SetLogLevel()

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

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

◆ SetRealmId()

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

References appenders.

◆ SetSynchronous()

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

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

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