Files
TCPlayerbotCore/src/common/Logging/Log.cpp
T

400 lines
11 KiB
C++
Raw Normal View History

/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "Log.h"
#include "AppenderConsole.h"
#include "AppenderFile.h"
2017-05-11 22:29:51 +02:00
#include "Common.h"
#include "Config.h"
#include "Errors.h"
#include "Logger.h"
#include "LogMessage.h"
#include "LogOperation.h"
#include "Strand.h"
2017-05-11 22:29:51 +02:00
#include "Util.h"
#include <chrono>
#include <sstream>
2009-10-17 15:51:44 -07:00
Log::Log() : AppenderId(0), lowestLogLevel(LOG_LEVEL_FATAL), _ioContext(nullptr), _strand(nullptr)
2008-11-25 16:36:50 -06:00
{
m_logsTimestamp = "_" + GetTimestampStr();
RegisterAppender<AppenderConsole>();
RegisterAppender<AppenderFile>();
2008-11-25 16:36:50 -06:00
}
2009-10-17 15:51:44 -07:00
2009-03-19 21:13:52 +01:00
Log::~Log()
2008-10-02 16:23:55 -05:00
{
delete _strand;
Close();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
uint8 Log::NextAppenderId()
2008-10-02 16:23:55 -05:00
{
return AppenderId++;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
Appender* Log::GetAppenderByName(std::string const& name)
2008-10-02 16:23:55 -05:00
{
2017-05-11 22:29:51 +02:00
auto it = appenders.begin();
while (it != appenders.end() && it->second && it->second->getName() != name)
++it;
2009-10-17 15:51:44 -07:00
2017-05-11 22:29:51 +02:00
return it == appenders.end() ? nullptr : it->second.get();
}
2009-10-17 15:51:44 -07:00
void Log::CreateAppenderFromConfig(std::string const& appenderName)
{
if (appenderName.empty())
return;
2009-10-17 15:51:44 -07:00
// Format = type, level, flags, optional1, optional2
// if type = File. optional1 = file and option2 = mode
// if type = Console. optional1 = Color
2017-11-11 20:27:30 +01:00
std::string options = sConfigMgr->GetStringDefault(appenderName, "");
2013-11-11 14:34:44 +01:00
Tokenizer tokens(options, ',');
2017-05-11 22:29:51 +02:00
auto iter = tokens.begin();
2013-11-11 14:34:44 +01:00
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;
}
2009-10-17 15:51:44 -07:00
AppenderFlags flags = APPENDER_FLAGS_NONE;
2013-11-11 14:34:44 +01:00
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;
}
2009-10-17 15:51:44 -07:00
if (size > 2)
2013-11-11 14:34:44 +01:00
flags = AppenderFlags(atoi(*iter++));
auto factoryFunction = appenderFactory.find(type);
if (factoryFunction == appenderFactory.end())
2008-10-02 16:23:55 -05:00
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown type %d for appender %s\n", type, name.c_str());
return;
}
try
{
2017-05-11 22:29:51 +02:00
Appender* appender = factoryFunction->second(NextAppenderId(), name, level, flags, std::vector<char const*>(iter, tokens.end()));
appenders[appender->getId()].reset(appender);
}
catch (InvalidAppenderArgsException const& iaae)
{
2015-08-16 00:45:07 +01:00
fprintf(stderr, "%s", iaae.what());
2008-10-02 16:23:55 -05:00
}
}
void Log::CreateLoggerFromConfig(std::string const& appenderName)
{
if (appenderName.empty())
return;
LogLevel level = LOG_LEVEL_DISABLED;
2012-12-31 20:43:14 +01:00
uint8 type = uint8(-1);
2017-11-11 20:27:30 +01:00
std::string options = sConfigMgr->GetStringDefault(appenderName, "");
std::string name = appenderName.substr(7);
2009-10-17 15:51:44 -07:00
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;
}
2011-09-08 23:00:26 -03:00
2017-05-11 22:29:51 +02:00
std::unique_ptr<Logger>& logger = loggers[name];
if (logger)
{
fprintf(stderr, "Error while configuring Logger %s. Already defined\n", name.c_str());
return;
}
2013-11-11 14:34:44 +01:00
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;
}
2011-09-08 23:00:26 -03:00
2015-03-02 22:16:44 +01:00
if (level < lowestLogLevel)
lowestLogLevel = level;
logger = std::make_unique<Logger>(name, level);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
2009-10-17 15:51:44 -07:00
std::istringstream ss(*iter);
std::string str;
ss >> str;
while (ss)
2008-11-25 16:36:50 -06:00
{
if (Appender* appender = GetAppenderByName(str))
{
2017-05-11 22:29:51 +02:00
logger->addAppender(appender->getId(), appender);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str());
}
2008-11-25 16:36:50 -06:00
else
fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist", str.c_str(), name.c_str());
ss >> str;
2008-11-25 16:36:50 -06:00
}
}
2009-10-17 15:51:44 -07:00
void Log::ReadAppendersFromConfig()
2008-11-25 16:36:50 -06:00
{
2017-05-11 22:29:51 +02:00
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Appender.");
for (std::string const& appenderName : keys)
CreateAppenderFromConfig(appenderName);
2008-11-25 16:36:50 -06:00
}
2009-10-17 15:51:44 -07:00
void Log::ReadLoggersFromConfig()
{
2017-05-11 22:29:51 +02:00
std::vector<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
for (std::string const& loggerName : keys)
CreateLoggerFromConfig(loggerName);
2009-10-17 15:51:44 -07:00
// 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
2017-05-11 22:29:51 +02:00
AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, std::vector<char const*>());
appenders[appender->getId()].reset(appender);
2017-05-11 22:29:51 +02:00
Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR);
rootLogger->addAppender(appender->getId(), appender);
loggers[LOGGER_ROOT].reset(rootLogger);
2017-05-11 22:29:51 +02:00
Logger* serverLogger = new Logger("server", LOG_LEVEL_INFO);
serverLogger->addAppender(appender->getId(), appender);
loggers["server"].reset(serverLogger);
}
}
2009-10-17 15:51:44 -07:00
2017-05-11 22:29:51 +02:00
void Log::RegisterAppender(uint8 index, AppenderCreatorFn appenderCreateFn)
{
auto itr = appenderFactory.find(index);
ASSERT(itr == appenderFactory.end());
appenderFactory[index] = appenderCreateFn;
}
void Log::outMessage(std::string const& filter, LogLevel level, std::string&& message)
2017-05-11 22:29:51 +02:00
{
write(std::make_unique<LogMessage>(level, filter, std::move(message)));
2017-05-11 22:29:51 +02:00
}
void Log::outCommand(std::string&& message, std::string&& param1)
{
write(std::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm", std::move(message), std::move(param1)));
2017-05-11 22:29:51 +02:00
}
2015-03-11 10:06:24 +01:00
void Log::write(std::unique_ptr<LogMessage>&& msg) const
2009-03-20 18:16:36 +01:00
{
Logger const* logger = GetLoggerByType(msg->type);
if (_ioContext)
{
std::shared_ptr<LogOperation> logOperation = std::make_shared<LogOperation>(logger, std::move(msg));
Trinity::Asio::post(*_ioContext, Trinity::Asio::bind_executor(*_strand, [logOperation]() { logOperation->call(); }));
}
else
2015-03-11 10:06:24 +01:00
logger->write(msg.get());
2009-03-20 18:16:36 +01:00
}
2009-10-17 15:51:44 -07:00
2017-05-11 22:29:51 +02:00
Logger const* Log::GetLoggerByType(std::string const& type) const
{
auto it = loggers.find(type);
if (it != loggers.end())
return it->second.get();
if (type == LOGGER_ROOT)
2020-08-14 17:06:03 +02:00
return nullptr;
2017-05-11 22:29:51 +02:00
std::string parentLogger = LOGGER_ROOT;
2017-02-18 17:22:57 +01:00
size_t found = type.find_last_of('.');
2017-05-11 22:29:51 +02:00
if (found != std::string::npos)
parentLogger = type.substr(0, found);
return GetLoggerByType(parentLogger);
}
2008-10-02 16:23:55 -05:00
std::string Log::GetTimestampStr()
{
2014-06-08 20:08:43 +02:00
time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
2014-06-22 15:42:46 +02:00
std::tm aTm;
localtime_r(&tt, &aTm);
2014-06-08 20:08:43 +02:00
2008-10-02 16:23:55 -05:00
// 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)
2016-12-24 13:08:41 +01:00
try
{
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);
}
catch (std::exception const& ex)
{
fprintf(stderr, "Failed to initialize timestamp part of log filename! %s", ex.what());
fflush(stderr);
ABORT();
}
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
bool Log::SetLogLevel(std::string const& name, char const* newLevelc, bool isLogger /* = true */)
2008-10-02 16:23:55 -05:00
{
LogLevel newLevel = LogLevel(atoi(newLevelc));
if (newLevel < 0)
return false;
2009-10-17 15:51:44 -07:00
if (isLogger)
2009-03-19 21:13:52 +01:00
{
2017-05-11 22:29:51 +02:00
auto it = loggers.begin();
while (it != loggers.end() && it->second->getName() != name)
++it;
2009-10-17 15:51:44 -07:00
if (it == loggers.end())
return false;
2009-10-17 15:51:44 -07:00
2017-05-11 22:29:51 +02:00
it->second->setLogLevel(newLevel);
if (newLevel != LOG_LEVEL_DISABLED && newLevel < lowestLogLevel)
lowestLogLevel = newLevel;
2008-10-02 16:23:55 -05:00
}
else
{
Appender* appender = GetAppenderByName(name);
if (!appender)
return false;
2009-10-17 15:51:44 -07:00
appender->setLogLevel(newLevel);
}
2009-10-17 15:51:44 -07:00
2013-11-11 14:34:44 +01:00
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";
2015-03-11 10:06:24 +01:00
std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()));
2012-10-22 10:37:39 +02:00
std::ostringstream param;
param << guid << '_' << name;
2012-10-22 10:37:39 +02:00
msg->param1 = param.str();
2015-03-11 10:06:24 +01:00
write(std::move(msg));
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
void Log::SetRealmId(uint32 id)
2008-10-02 16:23:55 -05:00
{
2017-05-11 22:29:51 +02:00
for (auto it = appenders.begin(); it != appenders.end(); ++it)
it->second->setRealmId(id);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
void Log::Close()
{
loggers.clear();
appenders.clear();
}
2017-05-11 22:29:51 +02:00
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;
}
Log* Log::instance()
{
static Log instance;
return &instance;
}
void Log::Initialize(Trinity::Asio::IoContext* ioContext)
{
if (ioContext)
{
_ioContext = ioContext;
_strand = new Trinity::Asio::Strand(*ioContext);
}
LoadFromConfig();
}
void Log::SetSynchronous()
{
delete _strand;
_strand = nullptr;
_ioContext = nullptr;
}
void Log::LoadFromConfig()
{
Close();
2015-03-02 22:16:44 +01:00
lowestLogLevel = LOG_LEVEL_FATAL;
AppenderId = 0;
2013-07-15 17:31:44 +02:00
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('/');
2013-11-11 14:34:44 +01:00
ReadAppendersFromConfig();
ReadLoggersFromConfig();
}