Legends-of-Azeroth-Pandaria-5.4.8

Форк
0
392 строки · 11.7 Кб
1
/*
2
* This file is part of the Pandaria 5.4.8 Project. See THANKS file for Copyright information
3
*
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation; either version 2 of the License, or (at your
7
* option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License along
15
* with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17

18
#include "Log.h"
19
#include "AppenderConsole.h"
20
#include "AppenderFile.h"
21
#include "Common.h"
22
#include "Config.h"
23
#include "Errors.h"
24
#include "Logger.h"
25
#include "LogMessage.h"
26
#include "LogOperation.h"
27
#include "Strand.h"
28
#include "StringConvert.h"
29
#include "Util.h"
30
#include <chrono>
31
#include <sstream>
32

33
Log::Log() : AppenderId(0), lowestLogLevel(LOG_LEVEL_FATAL), _ioContext(nullptr), _strand(nullptr)
34
{
35
    m_logsTimestamp = "_" + GetTimestampStr();
36
    RegisterAppender<AppenderConsole>();
37
    RegisterAppender<AppenderFile>();
38
}
39

40
Log::~Log()
41
{
42
    delete _strand;
43
    Close();
44
}
45

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

51
Appender* Log::GetAppenderByName(std::string_view name)
52
{
53
    auto it = appenders.begin();
54
    while (it != appenders.end() && it->second && it->second->getName() != name)
55
        ++it;
56

57
    return it == appenders.end() ? nullptr : it->second.get();
58
}
59

60
void Log::CreateAppenderFromConfig(std::string const& appenderName)
61
{
62
    if (appenderName.empty())
63
        return;
64

65
    // Format = type, level, flags, optional1, optional2
66
    // if type = File. optional1 = file and option2 = mode
67
    // if type = Console. optional1 = Color
68
    std::string options = sConfigMgr->GetStringDefault(appenderName, "");
69

70
    std::vector<std::string_view> tokens = Trinity::Tokenize(options, ',', true);
71

72
    size_t const size = tokens.size();
73
    std::string name = appenderName.substr(9);
74

75
    if (size < 2)
76
    {
77
        fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong configuration for appender %s. Config line: %s\n", name.c_str(), options.c_str());
78
        return;
79
    }
80

81
    AppenderFlags flags = APPENDER_FLAGS_NONE;
82
    AppenderType type = AppenderType(Trinity::StringTo<uint8>(tokens[0]).value_or(APPENDER_INVALID));
83
    LogLevel level = LogLevel(Trinity::StringTo<uint8>(tokens[1]).value_or(LOG_LEVEL_INVALID));
84

85
    auto factoryFunction = appenderFactory.find(type);
86
    if (factoryFunction == appenderFactory.end())
87
    {
88
        fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown type '%s' for appender %s\n", std::string(tokens[0]).c_str(), name.c_str());
89
        return;
90
    }
91

92
    if (level > NUM_ENABLED_LOG_LEVELS)
93
    {
94
        fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level '%s' for appender %s\n", std::string(tokens[1]).c_str(), name.c_str());
95
        return;
96
    }
97

98
    if (size > 2)
99
    {
100
        if (Optional<uint8> flagsVal = Trinity::StringTo<uint8>(tokens[2]))
101
            flags = AppenderFlags(*flagsVal);
102
        else
103
        {
104
            fprintf(stderr, "Log::CreateAppenderFromConfig: Unknown flags '%s' for appender %s\n", std::string(tokens[2]).c_str(), name.c_str());
105
            return;
106
        }
107
    }
108

109
    try
110
    {
111
        Appender* appender = factoryFunction->second(NextAppenderId(), name, level, flags, tokens);
112
        appenders[appender->getId()].reset(appender);
113
    }
114
    catch (InvalidAppenderArgsException const& iaae)
115
    {
116
        fprintf(stderr, "%s\n", iaae.what());
117
    }
118
}
119

120
void Log::CreateLoggerFromConfig(std::string const& appenderName)
121
{
122
    if (appenderName.empty())
123
        return;
124

125
    LogLevel level = LOG_LEVEL_DISABLED;
126

127
    std::string options = sConfigMgr->GetStringDefault(appenderName, "");
128
    std::string name = appenderName.substr(7);
129

130
    if (options.empty())
131
    {
132
        fprintf(stderr, "Log::CreateLoggerFromConfig: Missing config option Logger.%s\n", name.c_str());
133
        return;
134
    }
135

136
    std::vector<std::string_view> tokens = Trinity::Tokenize(options, ',', true);
137

138
    if (tokens.size() != 2)
139
    {
140
        fprintf(stderr, "Log::CreateLoggerFromConfig: Wrong config option Logger.%s=%s\n", name.c_str(), options.c_str());
141
        return;
142
    }
143

144
    std::unique_ptr<Logger>& logger = loggers[name];
145
    if (logger)
146
    {
147
        fprintf(stderr, "Error while configuring Logger %s. Already defined\n", name.c_str());
148
        return;
149
    }
150

151
    level = LogLevel(Trinity::StringTo<uint8>(tokens[0]).value_or(LOG_LEVEL_INVALID));
152
    if (level > NUM_ENABLED_LOG_LEVELS)
153
    {
154
        fprintf(stderr, "Log::CreateLoggerFromConfig: Wrong Log Level '%s' for logger %s\n", std::string(tokens[0]).c_str(), name.c_str());
155
        return;
156
    }
157

158
    if (level < lowestLogLevel)
159
        lowestLogLevel = level;
160

161
    logger = std::make_unique<Logger>(name, level);
162
    //fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
163

164
    for (std::string_view appenderName : Trinity::Tokenize(tokens[1], ' ', false))
165
    {
166
        if (Appender* appender = GetAppenderByName(appenderName))
167
        {
168
            logger->addAppender(appender->getId(), appender);
169
            //fprintf(stdout, "Log::CreateLoggerFromConfig: Added Appender %s to Logger %s\n", appender->getName().c_str(), name.c_str());
170
        }
171
        else
172
            fprintf(stderr, "Error while configuring Appender %s in Logger %s. Appender does not exist\n", std::string(appenderName).c_str(), name.c_str());
173
    }
174
}
175

176
void Log::ReadAppendersFromConfig()
177
{
178
    std::vector<std::string> keys = sConfigMgr->GetKeysByString("Appender.");
179
    for (std::string const& appenderName : keys)
180
        CreateAppenderFromConfig(appenderName);
181
}
182

183
void Log::ReadLoggersFromConfig()
184
{
185
    std::vector<std::string> keys = sConfigMgr->GetKeysByString("Logger.");
186
    for (std::string const& loggerName : keys)
187
        CreateLoggerFromConfig(loggerName);
188

189
    // Bad config configuration, creating default config
190
    if (loggers.find(LOGGER_ROOT) == loggers.end())
191
    {
192
        fprintf(stderr, "Wrong Loggers configuration. Review your Logger config section.\n"
193
                        "Creating default loggers [root (Error), server (Info)] to console\n");
194

195
        Close(); // Clean any Logger or Appender created
196

197
        AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, {});
198
        appenders[appender->getId()].reset(appender);
199

200
        Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR);
201
        rootLogger->addAppender(appender->getId(), appender);
202
        loggers[LOGGER_ROOT].reset(rootLogger);
203

204
        Logger* serverLogger = new Logger("server", LOG_LEVEL_INFO);
205
        serverLogger->addAppender(appender->getId(), appender);
206
        loggers["server"].reset(serverLogger);
207
    }
208
}
209

210
void Log::RegisterAppender(uint8 index, AppenderCreatorFn appenderCreateFn)
211
{
212
    auto itr = appenderFactory.find(index);
213
    ASSERT(itr == appenderFactory.end());
214
    appenderFactory[index] = appenderCreateFn;
215
}
216

217
void Log::outMessage(std::string const& filter, LogLevel level, std::string&& message)
218
{
219
    write(std::make_unique<LogMessage>(level, filter, std::move(message)));
220
}
221

222
void Log::outCommand(std::string&& message, std::string&& param1)
223
{
224
    write(std::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm", std::move(message), std::move(param1)));
225
}
226

227
void Log::write(std::unique_ptr<LogMessage>&& msg) const
228
{
229
    Logger const* logger = GetLoggerByType(msg->type);
230

231
    if (_ioContext)
232
    {
233
        std::shared_ptr<LogOperation> logOperation = std::make_shared<LogOperation>(logger, std::move(msg));
234
        Trinity::Asio::post(*_ioContext, Trinity::Asio::bind_executor(*_strand, [logOperation]() { logOperation->call(); }));
235
    }
236
    else
237
        logger->write(msg.get());
238
}
239

240
Logger const* Log::GetLoggerByType(std::string const& type) const
241
{
242
    auto it = loggers.find(type);
243
    if (it != loggers.end())
244
        return it->second.get();
245

246
    if (type == LOGGER_ROOT)
247
        return nullptr;
248

249
    std::string parentLogger = LOGGER_ROOT;
250
    size_t found = type.find_last_of('.');
251
    if (found != std::string::npos)
252
        parentLogger = type.substr(0, found);
253

254
    return GetLoggerByType(parentLogger);
255
}
256

257
std::string Log::GetTimestampStr()
258
{
259
    time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
260

261
    std::tm aTm;
262
    localtime_r(&tt, &aTm);
263

264
    //       YYYY   year
265
    //       MM     month (2 digits 01-12)
266
    //       DD     day (2 digits 01-31)
267
    //       HH     hour (2 digits 00-23)
268
    //       MM     minutes (2 digits 00-59)
269
    //       SS     seconds (2 digits 00-59)
270
    return Trinity::StringFormat("%04d-%02d-%02d_%02d-%02d-%02d",
271
        aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
272
}
273

274
bool Log::SetLogLevel(std::string const& name, int32 newLeveli, bool isLogger /* = true */)
275
{
276
    if (newLeveli < 0)
277
        return false;
278

279
    LogLevel newLevel = LogLevel(newLeveli);
280

281
    if (isLogger)
282
    {
283
        auto it = loggers.begin();
284
        while (it != loggers.end() && it->second->getName() != name)
285
            ++it;
286

287
        if (it == loggers.end())
288
            return false;
289

290
        it->second->setLogLevel(newLevel);
291

292
        if (newLevel != LOG_LEVEL_DISABLED && newLevel < lowestLogLevel)
293
            lowestLogLevel = newLevel;
294
    }
295
    else
296
    {
297
        Appender* appender = GetAppenderByName(name);
298
        if (!appender)
299
            return false;
300

301
        appender->setLogLevel(newLevel);
302
    }
303

304
    return true;
305
}
306

307
void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const* name)
308
{
309
    if (!str || !ShouldLog("entities.player.dump", LOG_LEVEL_INFO))
310
        return;
311

312
    std::ostringstream ss;
313
    ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
314
       << ")\n" << str << "\n== END DUMP ==\n";
315

316
    std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()));
317
    std::ostringstream param;
318
    param << guid << '_' << name;
319

320
    msg->param1 = param.str();
321

322
    write(std::move(msg));
323
}
324

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

331
void Log::Close()
332
{
333
    loggers.clear();
334
    appenders.clear();
335
}
336

337
bool Log::ShouldLog(std::string const& type, LogLevel level) const
338
{
339
    // TODO: Use cache to store "Type.sub1.sub2": "Type" equivalence, should
340
    // Speed up in cases where requesting "Type.sub1.sub2" but only configured
341
    // Logger "Type"
342

343
    // Don't even look for a logger if the LogLevel is lower than lowest log levels across all loggers
344
    if (level < lowestLogLevel)
345
        return false;
346

347
    Logger const* logger = GetLoggerByType(type);
348
    if (!logger)
349
        return false;
350

351
    LogLevel logLevel = logger->getLogLevel();
352
    return logLevel != LOG_LEVEL_DISABLED && logLevel <= level;
353
}
354

355
Log* Log::instance()
356
{
357
    static Log instance;
358
    return &instance;
359
}
360

361
void Log::Initialize(Trinity::Asio::IoContext* ioContext)
362
{
363
    if (ioContext)
364
    {
365
        _ioContext = ioContext;
366
        _strand = new Trinity::Asio::Strand(*ioContext);
367
    }
368

369
    LoadFromConfig();
370
}
371

372
void Log::SetSynchronous()
373
{
374
    delete _strand;
375
    _strand = nullptr;
376
    _ioContext = nullptr;
377
}
378

379
void Log::LoadFromConfig()
380
{
381
    Close();
382

383
    lowestLogLevel = LOG_LEVEL_FATAL;
384
    AppenderId = 0;
385
    m_logsDir = sConfigMgr->GetStringDefault("LogsDir", "");
386
    if (!m_logsDir.empty())
387
        if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
388
            m_logsDir.push_back('/');
389

390
    ReadAppendersFromConfig();
391
    ReadLoggersFromConfig();
392
}
393

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.