aboutsummaryrefslogtreecommitdiff
path: root/src/common/Logging
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/Logging')
-rw-r--r--src/common/Logging/Appender.cpp109
-rw-r--r--src/common/Logging/Appender.h132
-rw-r--r--src/common/Logging/AppenderConsole.cpp200
-rw-r--r--src/common/Logging/AppenderConsole.h62
-rw-r--r--src/common/Logging/AppenderFile.cpp125
-rw-r--r--src/common/Logging/AppenderFile.h46
-rw-r--r--src/common/Logging/Log.cpp348
-rw-r--r--src/common/Logging/Log.h216
-rw-r--r--src/common/Logging/LogOperation.cpp25
-rw-r--r--src/common/Logging/LogOperation.h42
-rw-r--r--src/common/Logging/Logger.cpp64
-rw-r--r--src/common/Logging/Logger.h43
12 files changed, 1412 insertions, 0 deletions
diff --git a/src/common/Logging/Appender.cpp b/src/common/Logging/Appender.cpp
new file mode 100644
index 00000000000..d19ef8cf96f
--- /dev/null
+++ b/src/common/Logging/Appender.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Appender.h"
+#include "Common.h"
+#include "Util.h"
+#include "StringFormat.h"
+
+#include <utility>
+#include <sstream>
+
+std::string LogMessage::getTimeStr(time_t time)
+{
+ tm aTm;
+ localtime_r(&time, &aTm);
+ char buf[20];
+ snprintf(buf, 20, "%04d-%02d-%02d_%02d:%02d:%02d", aTm.tm_year+1900, aTm.tm_mon+1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+ return std::string(buf);
+}
+
+std::string LogMessage::getTimeStr()
+{
+ return getTimeStr(mtime);
+}
+
+Appender::Appender(uint8 _id, std::string const& _name, LogLevel _level /* = LOG_LEVEL_DISABLED */, AppenderFlags _flags /* = APPENDER_FLAGS_NONE */):
+id(_id), name(_name), level(_level), flags(_flags) { }
+
+Appender::~Appender() { }
+
+uint8 Appender::getId() const
+{
+ return id;
+}
+
+std::string const& Appender::getName() const
+{
+ return name;
+}
+
+LogLevel Appender::getLogLevel() const
+{
+ return level;
+}
+
+AppenderFlags Appender::getFlags() const
+{
+ return flags;
+}
+
+void Appender::setLogLevel(LogLevel _level)
+{
+ level = _level;
+}
+
+void Appender::write(LogMessage* message)
+{
+ if (!level || level > message->level)
+ return;
+
+ std::ostringstream ss;
+
+ if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
+ ss << message->getTimeStr() << ' ';
+
+ if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
+ ss << Trinity::StringFormat("%-5s ", Appender::getLogLevelString(message->level));
+
+ if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
+ ss << '[' << message->type << "] ";
+
+ message->prefix = ss.str();
+ _write(message);
+}
+
+const char* Appender::getLogLevelString(LogLevel level)
+{
+ switch (level)
+ {
+ case LOG_LEVEL_FATAL:
+ return "FATAL";
+ case LOG_LEVEL_ERROR:
+ return "ERROR";
+ case LOG_LEVEL_WARN:
+ return "WARN";
+ case LOG_LEVEL_INFO:
+ return "INFO";
+ case LOG_LEVEL_DEBUG:
+ return "DEBUG";
+ case LOG_LEVEL_TRACE:
+ return "TRACE";
+ default:
+ return "DISABLED";
+ }
+}
diff --git a/src/common/Logging/Appender.h b/src/common/Logging/Appender.h
new file mode 100644
index 00000000000..6382399a0b4
--- /dev/null
+++ b/src/common/Logging/Appender.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef APPENDER_H
+#define APPENDER_H
+
+#include <unordered_map>
+#include <stdexcept>
+#include <string>
+#include <time.h>
+#include <type_traits>
+#include <vector>
+#include <utility>
+#include "Define.h"
+
+// Values assigned have their equivalent in enum ACE_Log_Priority
+enum LogLevel
+{
+ LOG_LEVEL_DISABLED = 0,
+ LOG_LEVEL_TRACE = 1,
+ LOG_LEVEL_DEBUG = 2,
+ LOG_LEVEL_INFO = 3,
+ LOG_LEVEL_WARN = 4,
+ LOG_LEVEL_ERROR = 5,
+ LOG_LEVEL_FATAL = 6
+};
+
+const uint8 MaxLogLevels = 6;
+
+enum AppenderType
+{
+ APPENDER_NONE,
+ APPENDER_CONSOLE,
+ APPENDER_FILE,
+ APPENDER_DB
+};
+
+enum AppenderFlags
+{
+ APPENDER_FLAGS_NONE = 0x00,
+ APPENDER_FLAGS_PREFIX_TIMESTAMP = 0x01,
+ APPENDER_FLAGS_PREFIX_LOGLEVEL = 0x02,
+ APPENDER_FLAGS_PREFIX_LOGFILTERTYPE = 0x04,
+ APPENDER_FLAGS_USE_TIMESTAMP = 0x08, // only used by FileAppender
+ APPENDER_FLAGS_MAKE_FILE_BACKUP = 0x10 // only used by FileAppender
+};
+
+struct LogMessage
+{
+ LogMessage(LogLevel _level, std::string const& _type, std::string&& _text)
+ : level(_level), type(_type), text(std::forward<std::string>(_text)), mtime(time(NULL))
+ { }
+
+ LogMessage(LogMessage const& /*other*/) = delete;
+ LogMessage& operator=(LogMessage const& /*other*/) = delete;
+
+ static std::string getTimeStr(time_t time);
+ std::string getTimeStr();
+
+ LogLevel const level;
+ std::string const type;
+ std::string const text;
+ std::string prefix;
+ std::string param1;
+ time_t mtime;
+
+ ///@ Returns size of the log message content in bytes
+ uint32 Size() const
+ {
+ return static_cast<uint32>(prefix.size() + text.size());
+ }
+};
+
+class Appender
+{
+ public:
+ Appender(uint8 _id, std::string const& name, LogLevel level = LOG_LEVEL_DISABLED, AppenderFlags flags = APPENDER_FLAGS_NONE);
+ virtual ~Appender();
+
+ uint8 getId() const;
+ std::string const& getName() const;
+ virtual AppenderType getType() const = 0;
+ LogLevel getLogLevel() const;
+ AppenderFlags getFlags() const;
+
+ void setLogLevel(LogLevel);
+ void write(LogMessage* message);
+ static const char* getLogLevelString(LogLevel level);
+ virtual void setRealmId(uint32 /*realmId*/) { }
+
+ private:
+ virtual void _write(LogMessage const* /*message*/) = 0;
+
+ uint8 id;
+ std::string name;
+ LogLevel level;
+ AppenderFlags flags;
+};
+
+typedef std::unordered_map<uint8, Appender*> AppenderMap;
+
+typedef std::vector<char const*> ExtraAppenderArgs;
+typedef Appender*(*AppenderCreatorFn)(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, ExtraAppenderArgs extraArgs);
+typedef std::unordered_map<uint8, AppenderCreatorFn> AppenderCreatorMap;
+
+template<class AppenderImpl>
+Appender* CreateAppender(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, ExtraAppenderArgs extraArgs)
+{
+ return new AppenderImpl(id, name, level, flags, std::forward<ExtraAppenderArgs>(extraArgs));
+}
+
+class InvalidAppenderArgsException : public std::length_error
+{
+public:
+ explicit InvalidAppenderArgsException(std::string const& message) : std::length_error(message) { }
+};
+
+#endif
diff --git a/src/common/Logging/AppenderConsole.cpp b/src/common/Logging/AppenderConsole.cpp
new file mode 100644
index 00000000000..531df266aa1
--- /dev/null
+++ b/src/common/Logging/AppenderConsole.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sstream>
+
+#include "AppenderConsole.h"
+#include "Config.h"
+#include "Util.h"
+
+#if PLATFORM == PLATFORM_WINDOWS
+ #include <Windows.h>
+#endif
+
+AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, ExtraAppenderArgs extraArgs)
+ : Appender(id, name, level, flags), _colored(false)
+{
+ for (uint8 i = 0; i < MaxLogLevels; ++i)
+ _colors[i] = ColorTypes(MaxColors);
+
+ if (!extraArgs.empty())
+ InitColors(extraArgs[0]);
+}
+
+void AppenderConsole::InitColors(std::string const& str)
+{
+ if (str.empty())
+ {
+ _colored = false;
+ return;
+ }
+
+ int color[MaxLogLevels];
+
+ std::istringstream ss(str);
+
+ for (uint8 i = 0; i < MaxLogLevels; ++i)
+ {
+ ss >> color[i];
+
+ if (!ss)
+ return;
+
+ if (color[i] < 0 || color[i] >= MaxColors)
+ return;
+ }
+
+ for (uint8 i = 0; i < MaxLogLevels; ++i)
+ _colors[i] = ColorTypes(color[i]);
+
+ _colored = true;
+}
+
+void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+ static WORD WinColorFG[MaxColors] =
+ {
+ 0, // BLACK
+ FOREGROUND_RED, // RED
+ FOREGROUND_GREEN, // GREEN
+ FOREGROUND_RED | FOREGROUND_GREEN, // BROWN
+ FOREGROUND_BLUE, // BLUE
+ FOREGROUND_RED | FOREGROUND_BLUE, // MAGENTA
+ FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // WHITE
+ // YELLOW
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
+ // RED_BOLD
+ FOREGROUND_RED | FOREGROUND_INTENSITY,
+ // GREEN_BOLD
+ FOREGROUND_GREEN | FOREGROUND_INTENSITY,
+ FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD
+ // MAGENTA_BOLD
+ FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
+ // CYAN_BOLD
+ FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
+ // WHITE_BOLD
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
+ };
+
+ HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+ SetConsoleTextAttribute(hConsole, WinColorFG[color]);
+#else
+ enum ANSITextAttr
+ {
+ TA_NORMAL = 0,
+ TA_BOLD = 1,
+ TA_BLINK = 5,
+ TA_REVERSE = 7
+ };
+
+ enum ANSIFgTextAttr
+ {
+ FG_BLACK = 30,
+ FG_RED,
+ FG_GREEN,
+ FG_BROWN,
+ FG_BLUE,
+ FG_MAGENTA,
+ FG_CYAN,
+ FG_WHITE,
+ FG_YELLOW
+ };
+
+ enum ANSIBgTextAttr
+ {
+ BG_BLACK = 40,
+ BG_RED,
+ BG_GREEN,
+ BG_BROWN,
+ BG_BLUE,
+ BG_MAGENTA,
+ BG_CYAN,
+ BG_WHITE
+ };
+
+ static uint8 UnixColorFG[MaxColors] =
+ {
+ FG_BLACK, // BLACK
+ FG_RED, // RED
+ FG_GREEN, // GREEN
+ FG_BROWN, // BROWN
+ FG_BLUE, // BLUE
+ FG_MAGENTA, // MAGENTA
+ FG_CYAN, // CYAN
+ FG_WHITE, // WHITE
+ FG_YELLOW, // YELLOW
+ FG_RED, // LRED
+ FG_GREEN, // LGREEN
+ FG_BLUE, // LBLUE
+ FG_MAGENTA, // LMAGENTA
+ FG_CYAN, // LCYAN
+ FG_WHITE // LWHITE
+ };
+
+ fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < MaxColors ? ";1" : ""));
+ #endif
+}
+
+void AppenderConsole::ResetColor(bool stdout_stream)
+{
+ #if PLATFORM == PLATFORM_WINDOWS
+ HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+ SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
+ #else
+ fprintf((stdout_stream ? stdout : stderr), "\x1b[0m");
+ #endif
+}
+
+void AppenderConsole::_write(LogMessage const* message)
+{
+ bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL);
+
+ if (_colored)
+ {
+ uint8 index;
+ switch (message->level)
+ {
+ case LOG_LEVEL_TRACE:
+ index = 5;
+ break;
+ case LOG_LEVEL_DEBUG:
+ index = 4;
+ break;
+ case LOG_LEVEL_INFO:
+ index = 3;
+ break;
+ case LOG_LEVEL_WARN:
+ index = 2;
+ break;
+ case LOG_LEVEL_FATAL:
+ index = 0;
+ break;
+ case LOG_LEVEL_ERROR: // No break on purpose
+ default:
+ index = 1;
+ break;
+ }
+
+ SetColor(stdout_stream, _colors[index]);
+ utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
+ ResetColor(stdout_stream);
+ }
+ else
+ utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
+}
diff --git a/src/common/Logging/AppenderConsole.h b/src/common/Logging/AppenderConsole.h
new file mode 100644
index 00000000000..6b30505c6bd
--- /dev/null
+++ b/src/common/Logging/AppenderConsole.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef APPENDERCONSOLE_H
+#define APPENDERCONSOLE_H
+
+#include <string>
+#include "Appender.h"
+
+enum ColorTypes
+{
+ BLACK,
+ RED,
+ GREEN,
+ BROWN,
+ BLUE,
+ MAGENTA,
+ CYAN,
+ GREY,
+ YELLOW,
+ LRED,
+ LGREEN,
+ LBLUE,
+ LMAGENTA,
+ LCYAN,
+ WHITE
+};
+
+const uint8 MaxColors = uint8(WHITE) + 1;
+
+class AppenderConsole : public Appender
+{
+ public:
+ typedef std::integral_constant<AppenderType, APPENDER_CONSOLE>::type TypeIndex;
+
+ AppenderConsole(uint8 _id, std::string const& name, LogLevel level, AppenderFlags flags, ExtraAppenderArgs extraArgs);
+ void InitColors(const std::string& init_str);
+ AppenderType getType() const override { return TypeIndex::value; }
+
+ private:
+ void SetColor(bool stdout_stream, ColorTypes color);
+ void ResetColor(bool stdout_stream);
+ void _write(LogMessage const* message) override;
+ bool _colored;
+ ColorTypes _colors[MaxLogLevels];
+};
+
+#endif
diff --git a/src/common/Logging/AppenderFile.cpp b/src/common/Logging/AppenderFile.cpp
new file mode 100644
index 00000000000..bb15aed5e0b
--- /dev/null
+++ b/src/common/Logging/AppenderFile.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AppenderFile.h"
+#include "Common.h"
+#include "StringFormat.h"
+#include "Log.h"
+
+#if PLATFORM == PLATFORM_WINDOWS
+# include <Windows.h>
+#endif
+
+AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, ExtraAppenderArgs extraArgs) :
+ Appender(id, name, level, flags),
+ logfile(NULL),
+ _logDir(sLog->GetLogsDir()),
+ _maxFileSize(0),
+ _fileSize(0)
+{
+ if (extraArgs.empty())
+ throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Missing file name for appender %s\n", name.c_str()));
+
+ _fileName = extraArgs[0];
+
+ char const* mode = "a";
+ if (extraArgs.size() > 1)
+ mode = extraArgs[1];
+
+ if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
+ {
+ size_t dot_pos = _fileName.find_last_of(".");
+ if (dot_pos != std::string::npos)
+ _fileName.insert(dot_pos, sLog->GetLogsTimestamp());
+ else
+ _fileName += sLog->GetLogsTimestamp();
+ }
+
+ if (extraArgs.size() > 2)
+ _maxFileSize = atoi(extraArgs[2]);
+
+ _dynamicName = std::string::npos != _fileName.find("%s");
+ _backup = (flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0;
+
+ if (!_dynamicName)
+ logfile = OpenFile(_fileName, mode, !strcmp(mode, "w") && _backup);
+}
+
+AppenderFile::~AppenderFile()
+{
+ CloseFile();
+}
+
+void AppenderFile::_write(LogMessage const* message)
+{
+ bool exceedMaxSize = _maxFileSize > 0 && (_fileSize.load() + message->Size()) > _maxFileSize;
+
+ if (_dynamicName)
+ {
+ char namebuf[TRINITY_PATH_MAX];
+ snprintf(namebuf, TRINITY_PATH_MAX, _fileName.c_str(), message->param1.c_str());
+ // always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
+ FILE* file = OpenFile(namebuf, "a", _backup || exceedMaxSize);
+ if (!file)
+ return;
+ fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
+ fflush(file);
+ _fileSize += uint64(message->Size());
+ fclose(file);
+ return;
+ }
+ else if (exceedMaxSize)
+ logfile = OpenFile(_fileName, "w", true);
+
+ if (!logfile)
+ return;
+
+ fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
+ fflush(logfile);
+ _fileSize += uint64(message->Size());
+}
+
+FILE* AppenderFile::OpenFile(std::string const& filename, std::string const& mode, bool backup)
+{
+ std::string fullName(_logDir + filename);
+ if (backup)
+ {
+ CloseFile();
+ std::string newName(fullName);
+ newName.push_back('.');
+ newName.append(LogMessage::getTimeStr(time(NULL)));
+ std::replace(newName.begin(), newName.end(), ':', '-');
+ rename(fullName.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore
+ }
+
+ if (FILE* ret = fopen(fullName.c_str(), mode.c_str()))
+ {
+ _fileSize = ftell(ret);
+ return ret;
+ }
+
+ return NULL;
+}
+
+void AppenderFile::CloseFile()
+{
+ if (logfile)
+ {
+ fclose(logfile);
+ logfile = NULL;
+ }
+}
diff --git a/src/common/Logging/AppenderFile.h b/src/common/Logging/AppenderFile.h
new file mode 100644
index 00000000000..c2781eb1ee9
--- /dev/null
+++ b/src/common/Logging/AppenderFile.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef APPENDERFILE_H
+#define APPENDERFILE_H
+
+#include <atomic>
+#include "Appender.h"
+
+class AppenderFile : public Appender
+{
+ public:
+ typedef std::integral_constant<AppenderType, APPENDER_FILE>::type TypeIndex;
+
+ AppenderFile(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, ExtraAppenderArgs extraArgs);
+ ~AppenderFile();
+ FILE* OpenFile(std::string const& name, std::string const& mode, bool backup);
+ AppenderType getType() const override { return TypeIndex::value; }
+
+ private:
+ void CloseFile();
+ void _write(LogMessage const* message) override;
+ FILE* logfile;
+ std::string _fileName;
+ std::string _logDir;
+ bool _dynamicName;
+ bool _backup;
+ uint64 _maxFileSize;
+ std::atomic<uint64> _fileSize;
+};
+
+#endif
diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp
new file mode 100644
index 00000000000..c9ac4dfb9a2
--- /dev/null
+++ b/src/common/Logging/Log.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Log.h"
+#include "Common.h"
+#include "Config.h"
+#include "Util.h"
+#include "AppenderConsole.h"
+#include "AppenderFile.h"
+#include "LogOperation.h"
+
+#include <cstdarg>
+#include <cstdio>
+#include <sstream>
+
+Log::Log() : _ioService(nullptr), _strand(nullptr)
+{
+ m_logsTimestamp = "_" + GetTimestampStr();
+ RegisterAppender<AppenderConsole>();
+ RegisterAppender<AppenderFile>();
+}
+
+Log::~Log()
+{
+ delete _strand;
+ Close();
+}
+
+uint8 Log::NextAppenderId()
+{
+ return AppenderId++;
+}
+
+int32 GetConfigIntDefault(std::string base, const char* name, int32 value)
+{
+ base.append(name);
+ return sConfigMgr->GetIntDefault(base.c_str(), value);
+}
+
+std::string GetConfigStringDefault(std::string base, const char* name, const char* value)
+{
+ base.append(name);
+ return sConfigMgr->GetStringDefault(base.c_str(), value);
+}
+
+Appender* Log::GetAppenderByName(std::string const& name)
+{
+ AppenderMap::iterator it = appenders.begin();
+ while (it != appenders.end() && it->second && it->second->getName() != name)
+ ++it;
+
+ return it == appenders.end() ? NULL : it->second;
+}
+
+void Log::CreateAppenderFromConfig(std::string const& appenderName)
+{
+ if (appenderName.empty())
+ return;
+
+ // Format=type, level, flags, optional1, optional2
+ // if type = File. optional1 = file and option2 = mode
+ // if type = Console. optional1 = Color
+ std::string options = sConfigMgr->GetStringDefault(appenderName.c_str(), "");
+
+ Tokenizer tokens(options, ',');
+ Tokenizer::const_iterator iter = tokens.begin();
+
+ size_t size = tokens.size();
+ std::string name = appenderName.substr(9);
+
+ if (size < 2)
+ {
+ fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong configuration for appender %s. Config line: %s\n", name.c_str(), options.c_str());
+ return;
+ }
+
+ AppenderFlags flags = APPENDER_FLAGS_NONE;
+ AppenderType type = AppenderType(atoi(*iter++));
+ LogLevel level = LogLevel(atoi(*iter++));
+
+ if (level > LOG_LEVEL_FATAL)
+ {
+ fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level %d for appender %s\n", level, name.c_str());
+ return;
+ }
+
+ if (size > 2)
+ flags = AppenderFlags(atoi(*iter++));
+
+ auto factoryFunction = appenderFactory.find(type);
+ if (factoryFunction == appenderFactory.end())
+ {
+ fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown type %d for appender %s\n", type, name.c_str());
+ return;
+ }
+
+ try
+ {
+ Appender* appender = factoryFunction->second(NextAppenderId(), name, level, flags, ExtraAppenderArgs(iter, tokens.end()));
+ appenders[appender->getId()] = appender;
+ }
+ catch (InvalidAppenderArgsException const& iaae)
+ {
+ fprintf(stderr, "%s", iaae.what());
+ }
+}
+
+void Log::CreateLoggerFromConfig(std::string const& appenderName)
+{
+ if (appenderName.empty())
+ return;
+
+ LogLevel level = LOG_LEVEL_DISABLED;
+ uint8 type = uint8(-1);
+
+ std::string options = sConfigMgr->GetStringDefault(appenderName.c_str(), "");
+ std::string name = appenderName.substr(7);
+
+ if (options.empty())
+ {
+ fprintf(stderr, "Log::CreateLoggerFromConfig: Missing config option Logger.%s\n", name.c_str());
+ return;
+ }
+
+ Tokenizer tokens(options, ',');
+ Tokenizer::const_iterator iter = tokens.begin();
+
+ if (tokens.size() != 2)
+ {
+ fprintf(stderr, "Log::CreateLoggerFromConfig: Wrong config option Logger.%s=%s\n", name.c_str(), options.c_str());
+ return;
+ }
+
+ Logger& logger = loggers[name];
+ if (!logger.getName().empty())
+ {
+ fprintf(stderr, "Error while configuring Logger %s. Already defined\n", name.c_str());
+ return;
+ }
+
+ level = LogLevel(atoi(*iter++));
+ if (level > LOG_LEVEL_FATAL)
+ {
+ fprintf(stderr, "Log::CreateLoggerFromConfig: Wrong Log Level %u for logger %s\n", type, name.c_str());
+ return;
+ }
+
+ if (level < lowestLogLevel)
+ lowestLogLevel = level;
+
+ logger.Create(name, level);
+ //fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
+
+ std::istringstream ss(*iter);
+ std::string str;
+
+ ss >> str;
+ while (ss)
+ {
+ if (Appender* appender = GetAppenderByName(str))
+ {
+ logger.addAppender(appender->getId(), appender);
+ //fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str());
+ }
+ else
+ fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist", str.c_str(), name.c_str());
+ ss >> str;
+ }
+}
+
+void Log::ReadAppendersFromConfig()
+{
+ std::list<std::string> keys = sConfigMgr->GetKeysByString("Appender.");
+
+ while (!keys.empty())
+ {
+ CreateAppenderFromConfig(keys.front());
+ keys.pop_front();
+ }
+}
+
+void Log::ReadLoggersFromConfig()
+{
+ std::list<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
+
+ while (!keys.empty())
+ {
+ CreateLoggerFromConfig(keys.front());
+ keys.pop_front();
+ }
+
+ // Bad config configuration, creating default config
+ if (loggers.find(LOGGER_ROOT) == loggers.end())
+ {
+ fprintf(stderr, "Wrong Loggers configuration. Review your Logger config section.\n"
+ "Creating default loggers [root (Error), server (Info)] to console\n");
+
+ Close(); // Clean any Logger or Appender created
+
+ AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, ExtraAppenderArgs());
+ appenders[appender->getId()] = appender;
+
+ Logger& logger = loggers[LOGGER_ROOT];
+ logger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR);
+ logger.addAppender(appender->getId(), appender);
+
+ logger = loggers["server"];
+ logger.Create("server", LOG_LEVEL_ERROR);
+ logger.addAppender(appender->getId(), appender);
+ }
+}
+
+void Log::write(std::unique_ptr<LogMessage>&& msg) const
+{
+ Logger const* logger = GetLoggerByType(msg->type);
+
+ if (_ioService)
+ {
+ auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, std::move(msg)));
+
+ _ioService->post(_strand->wrap([logOperation](){ logOperation->call(); }));
+ }
+ else
+ logger->write(msg.get());
+}
+
+std::string Log::GetTimestampStr()
+{
+ time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+
+ std::tm aTm;
+ localtime_r(&tt, &aTm);
+
+ // YYYY year
+ // MM month (2 digits 01-12)
+ // DD day (2 digits 01-31)
+ // HH hour (2 digits 00-23)
+ // MM minutes (2 digits 00-59)
+ // SS seconds (2 digits 00-59)
+ return Trinity::StringFormat("%04d-%02d-%02d_%02d-%02d-%02d",
+ aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+}
+
+bool Log::SetLogLevel(std::string const& name, const char* newLevelc, bool isLogger /* = true */)
+{
+ LogLevel newLevel = LogLevel(atoi(newLevelc));
+ if (newLevel < 0)
+ return false;
+
+ if (isLogger)
+ {
+ LoggerMap::iterator it = loggers.begin();
+ while (it != loggers.end() && it->second.getName() != name)
+ ++it;
+
+ if (it == loggers.end())
+ return false;
+
+ it->second.setLogLevel(newLevel);
+
+ if (newLevel != LOG_LEVEL_DISABLED && newLevel < lowestLogLevel)
+ lowestLogLevel = newLevel;
+ }
+ else
+ {
+ Appender* appender = GetAppenderByName(name);
+ if (!appender)
+ return false;
+
+ appender->setLogLevel(newLevel);
+ }
+
+ return true;
+}
+
+void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const* name)
+{
+ if (!str || !ShouldLog("entities.player.dump", LOG_LEVEL_INFO))
+ return;
+
+ std::ostringstream ss;
+ ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
+ << ")\n" << str << "\n== END DUMP ==\n";
+
+ std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()));
+ std::ostringstream param;
+ param << guid << '_' << name;
+
+ msg->param1 = param.str();
+
+ write(std::move(msg));
+}
+
+void Log::SetRealmId(uint32 id)
+{
+ for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it)
+ it->second->setRealmId(id);
+}
+
+void Log::Close()
+{
+ loggers.clear();
+ for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it)
+ delete it->second;
+
+ appenders.clear();
+}
+
+void Log::Initialize(boost::asio::io_service* ioService)
+{
+ if (ioService)
+ {
+ _ioService = ioService;
+ _strand = new boost::asio::strand(*ioService);
+ }
+
+ LoadFromConfig();
+}
+
+void Log::LoadFromConfig()
+{
+ Close();
+
+ lowestLogLevel = LOG_LEVEL_FATAL;
+ AppenderId = 0;
+ m_logsDir = sConfigMgr->GetStringDefault("LogsDir", "");
+ if (!m_logsDir.empty())
+ if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
+ m_logsDir.push_back('/');
+
+ ReadAppendersFromConfig();
+ ReadLoggersFromConfig();
+}
diff --git a/src/common/Logging/Log.h b/src/common/Logging/Log.h
new file mode 100644
index 00000000000..a15bb4ad485
--- /dev/null
+++ b/src/common/Logging/Log.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_LOG_H
+#define TRINITYCORE_LOG_H
+
+#include "Define.h"
+#include "Appender.h"
+#include "Logger.h"
+#include "StringFormat.h"
+#include "Common.h"
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/strand.hpp>
+
+#include <stdarg.h>
+#include <unordered_map>
+#include <string>
+#include <memory>
+
+#define LOGGER_ROOT "root"
+
+class Log
+{
+ typedef std::unordered_map<std::string, Logger> LoggerMap;
+
+ private:
+ Log();
+ ~Log();
+
+ public:
+
+ static Log* instance()
+ {
+ static Log instance;
+ return &instance;
+ }
+
+ void Initialize(boost::asio::io_service* ioService);
+ void LoadFromConfig();
+ void Close();
+ bool ShouldLog(std::string const& type, LogLevel level) const;
+ bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true);
+
+ template<typename Format, typename... Args>
+ inline void outMessage(std::string const& filter, LogLevel const level, Format&& fmt, Args&&... args)
+ {
+ write(Trinity::make_unique<LogMessage>(level, filter,
+ Trinity::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...)));
+ }
+
+ template<typename Format, typename... Args>
+ void outCommand(uint32 account, Format&& fmt, Args&&... args)
+ {
+ if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
+ return;
+
+ std::unique_ptr<LogMessage> msg =
+ Trinity::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm",
+ Trinity::StringFormat(std::forward<Format>(fmt), std::forward<Args>(args)...));
+
+ msg->param1 = std::to_string(account);
+
+ write(std::move(msg));
+ }
+
+ void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name);
+
+ void SetRealmId(uint32 id);
+
+ template<class AppenderImpl>
+ void RegisterAppender()
+ {
+ using Index = typename AppenderImpl::TypeIndex;
+ auto itr = appenderFactory.find(Index::value);
+ ASSERT(itr == appenderFactory.end());
+ appenderFactory[Index::value] = &CreateAppender<AppenderImpl>;
+ }
+
+ std::string const& GetLogsDir() const { return m_logsDir; }
+ std::string const& GetLogsTimestamp() const { return m_logsTimestamp; }
+
+ private:
+ static std::string GetTimestampStr();
+ void write(std::unique_ptr<LogMessage>&& msg) const;
+
+ Logger const* GetLoggerByType(std::string const& type) const;
+ Appender* GetAppenderByName(std::string const& name);
+ uint8 NextAppenderId();
+ void CreateAppenderFromConfig(std::string const& name);
+ void CreateLoggerFromConfig(std::string const& name);
+ void ReadAppendersFromConfig();
+ void ReadLoggersFromConfig();
+
+ AppenderCreatorMap appenderFactory;
+ AppenderMap appenders;
+ LoggerMap loggers;
+ uint8 AppenderId;
+ LogLevel lowestLogLevel;
+
+ std::string m_logsDir;
+ std::string m_logsTimestamp;
+
+ boost::asio::io_service* _ioService;
+ boost::asio::strand* _strand;
+};
+
+inline Logger const* Log::GetLoggerByType(std::string const& type) const
+{
+ LoggerMap::const_iterator it = loggers.find(type);
+ if (it != loggers.end())
+ return &(it->second);
+
+ if (type == LOGGER_ROOT)
+ return NULL;
+
+ std::string parentLogger = LOGGER_ROOT;
+ size_t found = type.find_last_of(".");
+ if (found != std::string::npos)
+ parentLogger = type.substr(0,found);
+
+ return GetLoggerByType(parentLogger);
+}
+
+inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
+{
+ // TODO: Use cache to store "Type.sub1.sub2": "Type" equivalence, should
+ // Speed up in cases where requesting "Type.sub1.sub2" but only configured
+ // Logger "Type"
+
+ // Don't even look for a logger if the LogLevel is lower than lowest log levels across all loggers
+ if (level < lowestLogLevel)
+ return false;
+
+ Logger const* logger = GetLoggerByType(type);
+ if (!logger)
+ return false;
+
+ LogLevel logLevel = logger->getLogLevel();
+ return logLevel != LOG_LEVEL_DISABLED && logLevel <= level;
+}
+
+#define sLog Log::instance()
+
+#define LOG_EXCEPTION_FREE(filterType__, level__, ...) \
+ { \
+ try \
+ { \
+ sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ } \
+ catch (std::exception& e) \
+ { \
+ sLog->outMessage("server", LOG_LEVEL_ERROR, "Wrong format occurred (%s) at %s:%u.", \
+ e.what(), __FILE__, __LINE__); \
+ } \
+ }
+
+#if PLATFORM != PLATFORM_WINDOWS
+void check_args(const char*, ...) ATTR_PRINTF(1, 2);
+void check_args(std::string const&, ...);
+
+// This will catch format errors on build time
+#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
+ do { \
+ if (sLog->ShouldLog(filterType__, level__)) \
+ { \
+ if (false) \
+ check_args(__VA_ARGS__); \
+ \
+ LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
+ } \
+ } while (0)
+#else
+#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4127)) \
+ do { \
+ if (sLog->ShouldLog(filterType__, level__)) \
+ LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
+ } while (0) \
+ __pragma(warning(pop))
+#endif
+
+#define TC_LOG_TRACE(filterType__, ...) \
+ TC_LOG_MESSAGE_BODY(filterType__, LOG_LEVEL_TRACE, __VA_ARGS__)
+
+#define TC_LOG_DEBUG(filterType__, ...) \
+ TC_LOG_MESSAGE_BODY(filterType__, LOG_LEVEL_DEBUG, __VA_ARGS__)
+
+#define TC_LOG_INFO(filterType__, ...) \
+ TC_LOG_MESSAGE_BODY(filterType__, LOG_LEVEL_INFO, __VA_ARGS__)
+
+#define TC_LOG_WARN(filterType__, ...) \
+ TC_LOG_MESSAGE_BODY(filterType__, LOG_LEVEL_WARN, __VA_ARGS__)
+
+#define TC_LOG_ERROR(filterType__, ...) \
+ TC_LOG_MESSAGE_BODY(filterType__, LOG_LEVEL_ERROR, __VA_ARGS__)
+
+#define TC_LOG_FATAL(filterType__, ...) \
+ TC_LOG_MESSAGE_BODY(filterType__, LOG_LEVEL_FATAL, __VA_ARGS__)
+
+#endif
diff --git a/src/common/Logging/LogOperation.cpp b/src/common/Logging/LogOperation.cpp
new file mode 100644
index 00000000000..bcd923c705e
--- /dev/null
+++ b/src/common/Logging/LogOperation.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "LogOperation.h"
+#include "Logger.h"
+
+int LogOperation::call()
+{
+ logger->write(msg.get());
+ return 0;
+}
diff --git a/src/common/Logging/LogOperation.h b/src/common/Logging/LogOperation.h
new file mode 100644
index 00000000000..ffdd35c3c09
--- /dev/null
+++ b/src/common/Logging/LogOperation.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOGOPERATION_H
+#define LOGOPERATION_H
+
+#include <memory>
+
+class Logger;
+struct LogMessage;
+
+class LogOperation
+{
+ public:
+ LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg)
+ : logger(_logger), msg(std::forward<std::unique_ptr<LogMessage>>(_msg))
+ { }
+
+ ~LogOperation() { }
+
+ int call();
+
+ protected:
+ Logger const* logger;
+ std::unique_ptr<LogMessage> msg;
+};
+
+#endif
diff --git a/src/common/Logging/Logger.cpp b/src/common/Logging/Logger.cpp
new file mode 100644
index 00000000000..3b02eb47575
--- /dev/null
+++ b/src/common/Logging/Logger.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Logger.h"
+
+Logger::Logger(): name(""), level(LOG_LEVEL_DISABLED) { }
+
+void Logger::Create(std::string const& _name, LogLevel _level)
+{
+ name = _name;
+ level = _level;
+}
+
+std::string const& Logger::getName() const
+{
+ return name;
+}
+
+LogLevel Logger::getLogLevel() const
+{
+ return level;
+}
+
+void Logger::addAppender(uint8 id, Appender* appender)
+{
+ appenders[id] = appender;
+}
+
+void Logger::delAppender(uint8 id)
+{
+ appenders.erase(id);
+}
+
+void Logger::setLogLevel(LogLevel _level)
+{
+ level = _level;
+}
+
+void Logger::write(LogMessage* message) const
+{
+ if (!level || level > message->level || message->text.empty())
+ {
+ //fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), getLogLevel(), message.text.c_str(), message.level);
+ return;
+ }
+
+ for (AppenderMap::const_iterator it = appenders.begin(); it != appenders.end(); ++it)
+ if (it->second)
+ it->second->write(message);
+}
diff --git a/src/common/Logging/Logger.h b/src/common/Logging/Logger.h
new file mode 100644
index 00000000000..1aee75c5d72
--- /dev/null
+++ b/src/common/Logging/Logger.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOGGER_H
+#define LOGGER_H
+
+#include "Appender.h"
+
+class Logger
+{
+ public:
+ Logger();
+
+ void Create(std::string const& name, LogLevel level);
+ void addAppender(uint8 type, Appender *);
+ void delAppender(uint8 type);
+
+ std::string const& getName() const;
+ LogLevel getLogLevel() const;
+ void setLogLevel(LogLevel level);
+ void write(LogMessage* message) const;
+
+ private:
+ std::string name;
+ LogLevel level;
+ AppenderMap appenders;
+};
+
+#endif