Updated the logging system
This commit is contained in:
parent
41fb8415cd
commit
b9e2da8bb4
|
@ -203,11 +203,11 @@ std::shared_ptr<BasicChannel> BasicChannelTree::findChannelByPath(const std::str
|
||||||
index = found + 1;
|
index = found + 1;
|
||||||
} while (index != 0 && entries.size() <= maxChannelDeep);
|
} while (index != 0 && entries.size() <= maxChannelDeep);
|
||||||
|
|
||||||
debugMessage("Parsed channel path '" + path + "'. Entries:");
|
debugMessage(LOG_GENERAL, "Parsed channel path \"{}\". Entries:", path);
|
||||||
std::shared_ptr<BasicChannel> current = nullptr;
|
std::shared_ptr<BasicChannel> current = nullptr;
|
||||||
for (const auto &name : entries) {
|
for (const auto &name : entries) {
|
||||||
current = this->findChannel(name, current);
|
current = this->findChannel(name, current);
|
||||||
debugMessage(" - '" + name + "' (" + (current ? "found" : "unknown") + ")");
|
debugMessage(LOG_GENERAL, " - \"{}\" {}", name, (current ? "found" : "unknown"));
|
||||||
if (!current) break;
|
if (!current) break;
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
|
|
|
@ -1,118 +1,119 @@
|
||||||
#include "LogUtils.h"
|
#include "LogUtils.h"
|
||||||
#include "LogSinks.h"
|
#include "LogSinks.h"
|
||||||
#include <iomanip>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/formatter.h>
|
||||||
#include <experimental/filesystem>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace spdlog;
|
using namespace spdlog;
|
||||||
namespace fs = std::experimental::filesystem;
|
|
||||||
|
|
||||||
namespace logger {
|
namespace logger {
|
||||||
void TerminalSink::log(const spdlog::details::log_msg &msg) {
|
void TerminalSink::sink_it_(const spdlog::details::log_msg &msg) {
|
||||||
|
memory_buf_t formatted;
|
||||||
|
this->formatter_->format(msg, formatted);
|
||||||
|
|
||||||
|
std::string_view message{formatted.data(), formatted.size()};
|
||||||
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
#ifdef HAVE_CXX_TERMINAL
|
||||||
if (terminal::active()) {
|
if (terminal::active()) {
|
||||||
auto strMsg = msg.formatted.str();
|
//Split the string at new lines
|
||||||
size_t index = 0;
|
size_t index{0}, found{0};
|
||||||
do {
|
do {
|
||||||
auto eIndex = strMsg.find('\n', index);
|
found = message.find('\n', index);
|
||||||
auto str = terminal::parseCharacterCodes(strMsg.substr(index, eIndex - index));
|
const auto length = (found == -1 ? message.length() : found) - index;
|
||||||
terminal::instance()->writeMessage(str);
|
const auto line = message.substr(index, length);
|
||||||
index = eIndex + 1;
|
|
||||||
} while (index != 0 && index < strMsg.length()); //if eindex == npos and we add the 1 we get 0 :)
|
index = found;
|
||||||
|
if(length == 0) continue;
|
||||||
|
|
||||||
|
terminal::instance()->writeMessage(std::string{line});
|
||||||
|
} while(++index);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
cout << msg.formatted.str();
|
cout << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalSink::flush() {}
|
void TerminalSink::flush_() {}
|
||||||
|
|
||||||
bool TerminalSink::should_log_(const details::log_msg &msg) const {
|
|
||||||
auto _force_message = dynamic_cast<const ::logger::force_log_msg*>(&msg);
|
|
||||||
if(_force_message && _force_message->force)
|
|
||||||
return true;
|
|
||||||
return sink::should_log_(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
ColoredFileSink::ColoredFileSink(const filename_t &base_filename, size_t max_size, size_t max_files)
|
inline void append_time(const log_clock::time_point& point, memory_buf_t& dest) {
|
||||||
: rotating_file_sink(
|
|
||||||
base_filename, max_size, max_files) {}
|
|
||||||
|
|
||||||
void ColoredFileSink::_sink_it(const details::log_msg &msg) {
|
|
||||||
details::log_msg _clone;
|
|
||||||
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
|
||||||
if (::logger::currentConfig()->file_colored)
|
|
||||||
_clone.formatted << ANSI_RESET << terminal::parseCharacterCodes(msg.formatted.str());
|
|
||||||
else
|
|
||||||
_clone.formatted << terminal::stripCharacterCodes(msg.formatted.str());
|
|
||||||
#else
|
|
||||||
_clone.formatted << msg.formatted.str();
|
|
||||||
#endif
|
|
||||||
sinks::rotating_file_sink_mt::_sink_it(_clone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CostumeFormatter::format(spdlog::details::log_msg &msg) {
|
|
||||||
msg.formatted.clear();
|
|
||||||
|
|
||||||
string lvlName = level::to_str(msg.level);
|
|
||||||
transform(lvlName.begin(), lvlName.end(), lvlName.begin(), ::toupper);
|
|
||||||
auto org_length = lvlName.length();
|
|
||||||
|
|
||||||
string msgColor;
|
|
||||||
string msgSuffix;
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
|
||||||
switch (msg.level) {
|
|
||||||
case level::trace:
|
|
||||||
lvlName = "§9" + lvlName;
|
|
||||||
break;
|
|
||||||
case level::info:
|
|
||||||
lvlName = "§e" + lvlName;
|
|
||||||
break;
|
|
||||||
case level::warn:
|
|
||||||
lvlName = "§6" + lvlName;
|
|
||||||
break;
|
|
||||||
case level::err:
|
|
||||||
lvlName = "§4" + lvlName;
|
|
||||||
break;
|
|
||||||
case level::critical:
|
|
||||||
lvlName = ANSI_BOLD ANSI_REVERSE ANSI_RED + lvlName;
|
|
||||||
msgColor = ANSI_BOLD ANSI_REVERSE ANSI_RED;
|
|
||||||
msgSuffix = ANSI_RESET;
|
|
||||||
break;
|
|
||||||
case level::debug:
|
|
||||||
lvlName = "§9" + lvlName;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto strMsg = msg.raw.str();
|
|
||||||
|
|
||||||
auto tp = std::chrono::system_clock::to_time_t(msg.time);
|
|
||||||
|
|
||||||
stringstream prefix;
|
|
||||||
prefix << "[" << std::put_time(std::localtime(&tp), "%F %T") << "] [" << lvlName << "§r] ";
|
|
||||||
for(size_t i = org_length; i < 5; i++)
|
|
||||||
prefix << " ";
|
|
||||||
prefix << msgColor;
|
|
||||||
|
|
||||||
size_t index = 0;
|
|
||||||
do {
|
|
||||||
auto eIndex = strMsg.find('\n', index);
|
|
||||||
auto m = strMsg.substr(index, eIndex - index);
|
|
||||||
msg.formatted << "§r" << prefix.str() << m << msgSuffix << "\n";
|
|
||||||
index = eIndex + 1; //if eindex == npos and we add the 1 we get 0 :)
|
|
||||||
} while (index != 0 && index < strMsg.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string CostumeFormatter::time(chrono::time_point<log_clock> point) {
|
|
||||||
std::time_t time = log_clock::to_time_t(point);
|
std::time_t time = log_clock::to_time_t(point);
|
||||||
std::tm timetm = *std::localtime(&time);
|
std::tm timetm = *std::localtime(&time);
|
||||||
char buffer[9];
|
|
||||||
strftime(buffer, 9, "%H:%M:%S", &timetm);
|
static constexpr auto max_length = 9;
|
||||||
return string(buffer, 8);
|
dest.reserve(dest.size() + max_length);
|
||||||
|
|
||||||
|
auto length = strftime(dest.end(), max_length, "%H:%M:%S", &timetm);
|
||||||
|
if(length < 0)
|
||||||
|
length = 0;
|
||||||
|
|
||||||
|
dest.resize(dest.size() + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::array<std::string_view, spdlog::level::off + 1> level_mapping_colored{
|
||||||
|
" [" ANSI_LIGHT_BLUE "TRACE" ANSI_RESET "] ",
|
||||||
|
" [" ANSI_LIGHT_BLUE "DEBUG" ANSI_RESET "] ",
|
||||||
|
" [" ANSI_YELLOW "INFO " ANSI_RESET "] ",
|
||||||
|
" [" ANSI_BROWN "WARNING " ANSI_RESET "] ",
|
||||||
|
" [" ANSI_RED "ERROR" ANSI_RESET "] ",
|
||||||
|
" [" ANSI_RED ANSI_BOLD ANSI_REVERSE "CRITICAL" ANSI_RESET "] ",
|
||||||
|
" [" ANSI_GRAY "OFF " ANSI_RESET "] "
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<std::string_view, spdlog::level::off + 1> level_mapping{
|
||||||
|
" [TRACE] ",
|
||||||
|
" [DEBUG] ",
|
||||||
|
" [INFO ] ",
|
||||||
|
" [WARNING ] ",
|
||||||
|
" [ERROR] ",
|
||||||
|
" [CRITICAL] ",
|
||||||
|
" [OFF ] "
|
||||||
|
};
|
||||||
|
|
||||||
|
void LogFormatter::format(const details::log_msg &msg, memory_buf_t &dest) {
|
||||||
|
const auto append = [&](const std::string_view& message) { dest.append(message.begin(), message.end()); };
|
||||||
|
|
||||||
|
dest.clear();
|
||||||
|
auto prefix_begin = dest.end();
|
||||||
|
//Time
|
||||||
|
{
|
||||||
|
dest.push_back('[');
|
||||||
|
append_time(msg.time, dest);
|
||||||
|
dest.push_back(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Level
|
||||||
|
{
|
||||||
|
const auto& mapping = this->_colored ? level_mapping_colored : level_mapping;
|
||||||
|
|
||||||
|
size_t level = msg.level.value;
|
||||||
|
if(level >= mapping.size())
|
||||||
|
level = mapping.size() - 1;
|
||||||
|
|
||||||
|
append(mapping[level]);
|
||||||
|
}
|
||||||
|
auto prefix_end = dest.end();
|
||||||
|
|
||||||
|
//Append the prefix to every line
|
||||||
|
std::string_view payload{msg.payload.data(), msg.payload.size()};
|
||||||
|
size_t index{0}, found{0};
|
||||||
|
while(true) {
|
||||||
|
found = payload.find(spdlog::details::os::default_eol, index);
|
||||||
|
auto line = payload.substr(index, (found == -1 ? payload.length() : found) - index);
|
||||||
|
|
||||||
|
auto colored = this->_colored ? terminal::parseCharacterCodes(std::string{line}) : terminal::stripCharacterCodes(std::string{line});
|
||||||
|
dest.append(colored.data(), colored.data() + colored.size());
|
||||||
|
|
||||||
|
index = found;
|
||||||
|
|
||||||
|
append(spdlog::details::os::default_eol);
|
||||||
|
if(++index)
|
||||||
|
dest.append(prefix_begin, prefix_end);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<formatter> LogFormatter::clone() const {
|
||||||
|
return std::make_unique<LogFormatter>(this->_colored);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,50 +1,37 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define SPDLOG_FINAL
|
|
||||||
#define SPDLOG_ALLOW_PROTECT
|
|
||||||
#define SPDLOG_NO_FINAL //We need to override the rotating logger
|
|
||||||
|
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
#include <spdlog/sinks/file_sinks.h>
|
#include <spdlog/sinks/base_sink.h>
|
||||||
|
|
||||||
namespace logger {
|
namespace logger {
|
||||||
struct force_log_msg : public spdlog::details::log_msg
|
class ColorCodeFormatter : public spdlog::formatter {
|
||||||
{
|
public:
|
||||||
force_log_msg() = default;
|
void format(const spdlog::details::log_msg &msg, spdlog::memory_buf_t &dest) override {
|
||||||
virtual ~force_log_msg() = default;
|
dest.append(msg.payload.begin(), msg.payload.end());
|
||||||
force_log_msg(const std::string *loggers_name, spdlog::level::level_enum lvl, bool force) : log_msg(loggers_name, lvl), force(force) { }
|
}
|
||||||
|
|
||||||
force_log_msg(const log_msg& other) = delete;
|
[[nodiscard]] std::unique_ptr<formatter> clone() const override {
|
||||||
force_log_msg(log_msg&& other) = delete;
|
return std::unique_ptr<ColorCodeFormatter>();
|
||||||
force_log_msg(const force_log_msg& other) = delete;
|
}
|
||||||
force_log_msg& operator=(force_log_msg&& other) = delete;
|
|
||||||
force_log_msg(force_log_msg&& other) = delete;
|
|
||||||
|
|
||||||
|
|
||||||
bool force;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TerminalSink : public spdlog::sinks::sink {
|
//TODO: Mutex really needed here?
|
||||||
|
class TerminalSink : public spdlog::sinks::base_sink<std::mutex> {
|
||||||
public:
|
public:
|
||||||
void log(const spdlog::details::log_msg &msg) override;
|
void sink_it_(const spdlog::details::log_msg &msg) override;
|
||||||
void flush();
|
void flush_() override;
|
||||||
|
|
||||||
bool should_log_(const spdlog::details::log_msg &msg) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ColoredFileSink : public spdlog::sinks::rotating_file_sink_mt {
|
class LogFormatter : public spdlog::formatter {
|
||||||
public:
|
public:
|
||||||
ColoredFileSink(const spdlog::filename_t &base_filename, size_t max_size, size_t max_files);
|
explicit LogFormatter(bool colored) : _colored{colored} {}
|
||||||
|
|
||||||
protected:
|
void format(const spdlog::details::log_msg &msg, spdlog::memory_buf_t &dest) override;
|
||||||
void _sink_it(const spdlog::details::log_msg &msg) override;
|
[[nodiscard]] std::unique_ptr<formatter> clone() const override;
|
||||||
};
|
|
||||||
|
|
||||||
class CostumeFormatter : public spdlog::formatter {
|
|
||||||
public:
|
|
||||||
void format(spdlog::details::log_msg &msg) override;
|
|
||||||
|
|
||||||
|
inline bool colored() const { return this->_colored; }
|
||||||
|
inline void colored(bool flag) { this->_colored = flag; }
|
||||||
private:
|
private:
|
||||||
inline std::string time(std::chrono::time_point <spdlog::log_clock> point);
|
bool _colored{true};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <CXXTerminal/Terminal.h>
|
#include <CXXTerminal/Terminal.h>
|
||||||
#include <spdlog/spdlog.h>
|
|
||||||
#include <experimental/filesystem>
|
#include <experimental/filesystem>
|
||||||
#include <StringVariable.h>
|
#include <StringVariable.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <spdlog/async.h>
|
||||||
|
#include <spdlog/sinks/rotating_file_sink.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace spdlog;
|
using namespace spdlog;
|
||||||
|
@ -20,28 +23,27 @@ namespace logger {
|
||||||
map<size_t, std::shared_ptr<spdlog::logger>> loggers;
|
map<size_t, std::shared_ptr<spdlog::logger>> loggers;
|
||||||
shared_ptr<LoggerConfig> logConfig;
|
shared_ptr<LoggerConfig> logConfig;
|
||||||
shared_ptr<::logger::TerminalSink> terminalSink;
|
shared_ptr<::logger::TerminalSink> terminalSink;
|
||||||
shared_ptr<::logger::CostumeFormatter> costumeFormatter;
|
|
||||||
|
|
||||||
shared_ptr<spdlog::logger> logger(int serverId) {
|
std::shared_ptr<spdlog::details::thread_pool> logging_threads{nullptr};
|
||||||
if(!::logger::currentConfig())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
size_t group = 0;
|
spdlog::level::level_enum min_level{spdlog::level::trace};
|
||||||
if(::logger::currentConfig()->vs_group_size > 0 && serverId > 0)
|
|
||||||
group = serverId / ::logger::currentConfig()->vs_group_size;
|
|
||||||
else group = -1;
|
|
||||||
|
|
||||||
if(loggers.count(group) == 0) {
|
void updater_logger_levels(const std::shared_ptr<spdlog::logger>& logger) {
|
||||||
lock_guard lock(loggerLock);
|
for(const auto& sink : logger->sinks())
|
||||||
if(loggers.count(group) > 0) return loggers[group];
|
if(dynamic_pointer_cast<TerminalSink>(sink)) {
|
||||||
//Create a new logger
|
sink->set_level(::logger::currentConfig()->terminalLevel);
|
||||||
if(group != 0 && group != -1)
|
} else if(dynamic_pointer_cast<spdlog::sinks::rotating_file_sink_mt>(sink)) {
|
||||||
logger(0)->debug("Creating new grouped logger for group {}", group);
|
sink->set_level(::logger::currentConfig()->logfileLevel);
|
||||||
|
} else if(dynamic_pointer_cast<spdlog::sinks::rotating_file_sink_st>(sink)) {
|
||||||
|
sink->set_level(::logger::currentConfig()->logfileLevel);
|
||||||
|
} else {
|
||||||
|
sink->set_level(min_level);
|
||||||
|
}
|
||||||
|
logger->set_level(min_level);
|
||||||
|
}
|
||||||
|
|
||||||
vector<spdlog::sink_ptr> sinks;
|
std::string generate_log_file(int group) {
|
||||||
string path;
|
return strvar::transform(logConfig->logPath,
|
||||||
if(logConfig->logfileLevel != spdlog::level::off) {
|
|
||||||
path = strvar::transform(logConfig->logPath,
|
|
||||||
strvar::StringValue{"group", group != -1 ? to_string(group) : "general"},
|
strvar::StringValue{"group", group != -1 ? to_string(group) : "general"},
|
||||||
strvar::FunctionValue("time", (strvar::FunctionValue::FValueFNEasy) [](std::deque<std::string> value) -> std::string {
|
strvar::FunctionValue("time", (strvar::FunctionValue::FValueFNEasy) [](std::deque<std::string> value) -> std::string {
|
||||||
auto pattern = !value.empty() ? value[0] : "%Y-%m-%d_%H:%M:%S";
|
auto pattern = !value.empty() ? value[0] : "%Y-%m-%d_%H:%M:%S";
|
||||||
|
@ -63,13 +65,55 @@ namespace logger {
|
||||||
return string(timeBuffer);
|
return string(timeBuffer);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mutex default_lock{};
|
||||||
|
bool default_setup{false};
|
||||||
|
|
||||||
|
std::shared_ptr<spdlog::logger> default_logger() {
|
||||||
|
lock_guard lock{default_lock};
|
||||||
|
if(!default_setup) {
|
||||||
|
default_setup = true;
|
||||||
|
|
||||||
|
spdlog::default_logger()->sinks().clear();
|
||||||
|
auto terminal_sink = make_shared<TerminalSink>();
|
||||||
|
terminal_sink->set_level(spdlog::level::trace);
|
||||||
|
spdlog::default_logger()->sinks().push_back(terminal_sink);
|
||||||
|
|
||||||
|
spdlog::default_logger()->set_formatter(std::make_unique<LogFormatter>(true));
|
||||||
|
}
|
||||||
|
return spdlog::default_logger();
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<spdlog::logger> logger(int serverId) {
|
||||||
|
if(!::logger::currentConfig())
|
||||||
|
return default_logger();
|
||||||
|
|
||||||
|
size_t group = 0;
|
||||||
|
if(::logger::currentConfig()->vs_group_size > 0 && serverId > 0)
|
||||||
|
group = serverId / ::logger::currentConfig()->vs_group_size;
|
||||||
|
else group = -1;
|
||||||
|
|
||||||
|
if(loggers.count(group) == 0) {
|
||||||
|
lock_guard lock(loggerLock);
|
||||||
|
if(loggers.count(group) > 0) return loggers[group];
|
||||||
|
//Create a new logger
|
||||||
|
if(group != 0 && group != -1)
|
||||||
|
logger(0)->debug("Creating new grouped logger for group {}", group);
|
||||||
|
|
||||||
|
vector<spdlog::sink_ptr> sinks;
|
||||||
|
string path;
|
||||||
|
if(logConfig->logfileLevel != spdlog::level::off) {
|
||||||
|
path = generate_log_file(group);
|
||||||
|
|
||||||
auto logFile = fs::u8path(path);
|
auto logFile = fs::u8path(path);
|
||||||
if(!logFile.parent_path().empty())
|
if(!logFile.parent_path().empty())
|
||||||
fs::create_directories(logFile.parent_path());
|
fs::create_directories(logFile.parent_path());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto fileSink = make_shared<ColoredFileSink>(logFile.string(), 1024 * 1024 * 50, 12);
|
auto sink = make_shared<spdlog::sinks::rotating_file_sink_mt>(logFile.string(), 1024 * 1024 * 50, 12);
|
||||||
sinks.push_back(fileSink);
|
sink->set_formatter(std::make_unique<LogFormatter>(::logger::currentConfig()->file_colored));
|
||||||
|
sinks.push_back(sink);
|
||||||
} catch(std::exception& ex) {
|
} catch(std::exception& ex) {
|
||||||
if(group != 0 && group != -1)
|
if(group != 0 && group != -1)
|
||||||
logger(0)->critical("Failed to create file for new log group: {}", ex.what());
|
logger(0)->critical("Failed to create file for new log group: {}", ex.what());
|
||||||
|
@ -77,25 +121,19 @@ namespace logger {
|
||||||
terminal::instance()->writeMessage("§4[CRITICAL] §eFailed to create main log file: " + string{ex.what()}, false);
|
terminal::instance()->writeMessage("§4[CRITICAL] §eFailed to create main log file: " + string{ex.what()}, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
path = "/dev/null (" + to_string(serverId) + ")";
|
path = "/dev/null (" + to_string(group) + ")";
|
||||||
}
|
}
|
||||||
sinks.push_back(terminalSink);
|
sinks.push_back(terminalSink);
|
||||||
|
|
||||||
|
if(!logging_threads)
|
||||||
|
logging_threads = std::make_shared<spdlog::details::thread_pool>(8192, 1); //Only one thread possible here, else elements get reordered
|
||||||
#ifdef ASYNC_LOG
|
#ifdef ASYNC_LOG
|
||||||
auto logger = create_async("Logger (" + path + ")", sinks.begin(), sinks.end(), 8192, async_overflow_policy::discard_log_msg, [](){}, std::chrono::milliseconds(500));
|
auto logger = std::make_shared<spdlog::async_logger>("Logger (" + path + ")", sinks.begin(), sinks.end(), logging_threads, async_overflow_policy::block);
|
||||||
#else
|
#else
|
||||||
|
//FIXME!
|
||||||
auto logger = create("Logger (" + path + ")", sinks.begin(), sinks.end());
|
auto logger = create("Logger (" + path + ")", sinks.begin(), sinks.end());
|
||||||
#endif
|
#endif
|
||||||
logger->set_formatter(costumeFormatter);
|
updater_logger_levels(logger);
|
||||||
for(const auto& sink : logger->sinks())
|
|
||||||
if(dynamic_pointer_cast<TerminalSink>(sink)) {
|
|
||||||
sink->set_level(::logger::currentConfig()->terminalLevel);
|
|
||||||
} else if(dynamic_pointer_cast<ColoredFileSink>(sink)) {
|
|
||||||
sink->set_level(::logger::currentConfig()->logfileLevel);
|
|
||||||
} else {
|
|
||||||
sink->set_level(min(::logger::currentConfig()->logfileLevel, ::logger::currentConfig()->terminalLevel));
|
|
||||||
}
|
|
||||||
logger->set_level(min(::logger::currentConfig()->logfileLevel, ::logger::currentConfig()->terminalLevel));
|
|
||||||
loggers[group] = logger;
|
loggers[group] = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,22 +150,63 @@ namespace logger {
|
||||||
|
|
||||||
terminalSink = make_shared<TerminalSink>();
|
terminalSink = make_shared<TerminalSink>();
|
||||||
terminalSink->set_level(::logger::currentConfig()->terminalLevel);
|
terminalSink->set_level(::logger::currentConfig()->terminalLevel);
|
||||||
costumeFormatter = make_shared<CostumeFormatter>();
|
terminalSink->set_formatter(std::make_unique<LogFormatter>(true));
|
||||||
|
min_level = ::min(::logger::currentConfig()->logfileLevel, ::logger::currentConfig()->terminalLevel);
|
||||||
|
|
||||||
logger(0)->debug("Log successfully started!");
|
logger(0)->debug("Log successfully started!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool should_log(spdlog::level::level_enum level) {
|
||||||
|
return level >= min_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(spdlog::level::forceable level, int server_id, const std::string_view& buffer) {
|
||||||
|
auto logger = ::logger::logger(server_id);
|
||||||
|
|
||||||
|
auto message_format = "§8{0:>5} | §r{1}";
|
||||||
|
if(server_id <= 0) {
|
||||||
|
switch (server_id) {
|
||||||
|
case LOG_INSTANCE:
|
||||||
|
message_format = "§8GLOBL | §r{1}";
|
||||||
|
break;
|
||||||
|
case LOG_QUERY:
|
||||||
|
message_format = "§8QUERY | §r{1}";
|
||||||
|
break;
|
||||||
|
case LOG_FT:
|
||||||
|
message_format = "§8 FILE | §r{1}";
|
||||||
|
break;
|
||||||
|
case LOG_GENERAL:
|
||||||
|
message_format = "§8 GEN | §r{1}";
|
||||||
|
break;
|
||||||
|
case LOG_LICENSE_CONTROLL:
|
||||||
|
message_format = "§8 CONTR | §r{1}";
|
||||||
|
break;
|
||||||
|
case LOG_LICENSE_WEB:
|
||||||
|
message_format = "§8 WEBST | §r{1}";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger->log(level, message_format, server_id, buffer);
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
//TODO better?
|
||||||
|
std::cerr << "An exception has raised while logging a message (" << ex.what() << "): " << buffer << "\n";
|
||||||
|
} catch(...) {
|
||||||
|
std::cerr << "An unknown exception has raised while logging a message: " << buffer << "\n";
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updateLogLevels() {
|
void updateLogLevels() {
|
||||||
lock_guard lock(loggerLock);
|
lock_guard lock(loggerLock);
|
||||||
for(const auto& loggerEntry : loggers) {
|
min_level = ::min(::logger::currentConfig()->logfileLevel, ::logger::currentConfig()->terminalLevel);
|
||||||
auto logger = loggerEntry.second;
|
for(const auto& logger : loggers) {
|
||||||
for(const auto& sink : logger->sinks())
|
updater_logger_levels(logger.second);
|
||||||
if(dynamic_pointer_cast<TerminalSink>(sink))
|
|
||||||
sink->set_level(::logger::currentConfig()->terminalLevel);
|
|
||||||
else if(dynamic_pointer_cast<ColoredFileSink>(sink))
|
|
||||||
sink->set_level(::logger::currentConfig()->logfileLevel);
|
|
||||||
else
|
|
||||||
sink->set_level(min(::logger::currentConfig()->logfileLevel, ::logger::currentConfig()->terminalLevel));
|
|
||||||
logger->set_level(min(::logger::currentConfig()->logfileLevel, ::logger::currentConfig()->terminalLevel));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +231,6 @@ namespace logger {
|
||||||
|
|
||||||
logConfig = nullptr;
|
logConfig = nullptr;
|
||||||
terminalSink = nullptr;
|
terminalSink = nullptr;
|
||||||
costumeFormatter = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define SPDLOG_EOL "\n"
|
||||||
#ifdef SPDLOG_FINAL
|
#ifdef SPDLOG_FINAL
|
||||||
#undef SPDLOG_FINAL
|
#undef SPDLOG_FINAL
|
||||||
#endif
|
#endif
|
||||||
#define SPDLOG_FINAL
|
#define SPDLOG_FINAL
|
||||||
#define SPDLOG_ALLOW_PROTECT
|
|
||||||
#define SPDLOG_NO_FINAL //We need to override the rotating logger
|
|
||||||
#ifdef byte
|
#ifdef byte
|
||||||
#undef byte
|
#undef byte
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <spdlog/logger.h>
|
#include <spdlog/logger.h>
|
||||||
|
#include <spdlog/fmt/fmt.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "../Definitions.h"
|
#include "../Definitions.h"
|
||||||
#include "LogSinks.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
#ifdef HAVE_CXX_TERMINAL
|
||||||
#include <CXXTerminal/Terminal.h>
|
#include <CXXTerminal/Terminal.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define lstream std::stringstream()
|
|
||||||
|
|
||||||
#ifdef log
|
#ifdef log
|
||||||
#undef log
|
#undef log
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,8 +38,29 @@ namespace logger {
|
||||||
extern const std::shared_ptr<LoggerConfig>& currentConfig();
|
extern const std::shared_ptr<LoggerConfig>& currentConfig();
|
||||||
extern void uninstall();
|
extern void uninstall();
|
||||||
|
|
||||||
|
extern bool should_log(spdlog::level::level_enum /* level */); //TODO: inline?
|
||||||
|
extern void log(spdlog::level::forceable /* level */, int /* server id */, const std::string_view& /* buffer */);
|
||||||
|
|
||||||
extern void updateLogLevels();
|
extern void updateLogLevels();
|
||||||
extern void flush();
|
extern void flush();
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
template <spdlog::level::level_enum level, typename... Args>
|
||||||
|
inline void do_log(bool forced, int serverId, const std::string& message, const Args&... args) {
|
||||||
|
if(!forced && !::logger::should_log(level)) return;
|
||||||
|
spdlog::memory_buf_t buffer{};
|
||||||
|
|
||||||
|
auto _logger = ::logger::logger(serverId);
|
||||||
|
std::string fmt_message;
|
||||||
|
try {
|
||||||
|
fmt_message = fmt::format(message, args...);
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
fmt_message = "failed to format message '" + std::string{message} + "': " + ex.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
::logger::log(spdlog::level::forceable{level, forced}, serverId, fmt_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LOG_LICENSE_CONTROLL (-0x10)
|
#define LOG_LICENSE_CONTROLL (-0x10)
|
||||||
|
@ -53,59 +71,10 @@ namespace logger {
|
||||||
#define LOG_FT (-3)
|
#define LOG_FT (-3)
|
||||||
#define LOG_GENERAL 0
|
#define LOG_GENERAL 0
|
||||||
|
|
||||||
#ifdef HAVE_CXX_TERMINAL
|
|
||||||
#define DEFINE_LOG_IMPL_NO_LOGGER(prefix, message) \
|
|
||||||
if(terminal::active()) \
|
|
||||||
terminal::instance()->writeMessage("[" + std::string(prefix) + "] " + message); \
|
|
||||||
else \
|
|
||||||
std::cout << "[" + std::string(prefix) + "] " + message << std::endl;
|
|
||||||
#else
|
|
||||||
#define DEFINE_LOG_IMPL_NO_LOGGER(prefix, message) \
|
|
||||||
std::cout << "[" + std::string(prefix) + "] " + message << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFINE_LOG_IMPL(name, level, _default_prefix) \
|
#define DEFINE_LOG_IMPL(name, level, _default_prefix) \
|
||||||
template <typename... Args> \
|
template <typename... Args> \
|
||||||
inline void name ##Fmt(bool forced, int serverId, const std::string& message, const Args&... args) { \
|
inline void name ##Fmt(bool forced, int serverId, const std::string& message, const Args&... args) { \
|
||||||
auto _logger = ::logger::logger(serverId); \
|
::logger::impl::do_log<level>(forced, serverId, message, args...); \
|
||||||
std::string fmt_message; \
|
|
||||||
try { \
|
|
||||||
fmt::MemoryWriter writer; \
|
|
||||||
writer.write(message, args...); \
|
|
||||||
fmt_message = writer.str(); \
|
|
||||||
} catch (const std::exception &ex) { \
|
|
||||||
fmt_message = "failed to format message '" + message + "': " + ex.what(); \
|
|
||||||
} \
|
|
||||||
if(!_logger) { \
|
|
||||||
DEFINE_LOG_IMPL_NO_LOGGER(_default_prefix, fmt_message); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
if (!_logger->should_log(level) && !forced) return; \
|
|
||||||
\
|
|
||||||
try { \
|
|
||||||
::logger::force_log_msg log_msg(&_logger->_name, level, forced); \
|
|
||||||
auto fmt = "§8{0:>5} | §r{1}"; \
|
|
||||||
if(serverId > 0); \
|
|
||||||
else if(serverId == LOG_INSTANCE) \
|
|
||||||
fmt = "§8GLOBL | §r{1}"; \
|
|
||||||
else if(serverId == LOG_QUERY) \
|
|
||||||
fmt = "§8QUERY | §r{1}"; \
|
|
||||||
else if(serverId == LOG_FT) \
|
|
||||||
fmt = "§8 FILE | §r{1}"; \
|
|
||||||
else if(serverId == LOG_GENERAL) \
|
|
||||||
fmt = "§8 GEN | §r{1}"; \
|
|
||||||
else if(serverId == LOG_LICENSE_CONTROLL) \
|
|
||||||
fmt = "§8 CONTR | §r{1}"; \
|
|
||||||
else if(serverId == LOG_LICENSE_WEB) \
|
|
||||||
fmt = "§8 WEBST | §r{1}"; \
|
|
||||||
log_msg.raw.write(fmt, serverId, fmt_message); \
|
|
||||||
_logger->_sink_it(log_msg); \
|
|
||||||
} catch (const std::exception &ex) { \
|
|
||||||
_logger->_err_handler(ex.what()); \
|
|
||||||
} catch(...) { \
|
|
||||||
_logger->_err_handler("Unknown exception in logger " + _logger->_name); \
|
|
||||||
throw; \
|
|
||||||
} \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_LOG_IMPL(logMessage, spdlog::level::info, "INFO")
|
DEFINE_LOG_IMPL(logMessage, spdlog::level::info, "INFO")
|
||||||
|
@ -119,9 +88,9 @@ DEFINE_LOG_IMPL(debugMessage, spdlog::level::debug, "DEBUG")
|
||||||
template <typename... Args> \
|
template <typename... Args> \
|
||||||
inline void name(int serverId, const std::string& message, const Args&... args){ name ##Fmt(false, serverId, message, args...); } \
|
inline void name(int serverId, const std::string& message, const Args&... args){ name ##Fmt(false, serverId, message, args...); } \
|
||||||
inline void name(int serverId, const std::string& message){ name ##Fmt(false, serverId, message); } \
|
inline void name(int serverId, const std::string& message){ name ##Fmt(false, serverId, message); } \
|
||||||
inline void name(int serverId, std::ostream& str){ std::stringstream s; s << str.rdbuf(); name(serverId, s.str()); } \
|
inline void name(int serverId, std::ostream& str) = delete; \
|
||||||
inline void name(const std::string& message) { name ##Fmt(false, 0, message); } \
|
inline void name(const std::string& message) = delete; \
|
||||||
inline void name(std::ostream& str){ std::stringstream s; s << str.rdbuf(); name(s.str()); } \
|
inline void name(std::ostream& str) = delete; \
|
||||||
inline void name(bool, int, const std::string&) = delete;
|
inline void name(bool, int, const std::string&) = delete;
|
||||||
|
|
||||||
LOG_METHOD(logError);
|
LOG_METHOD(logError);
|
||||||
|
|
|
@ -184,7 +184,7 @@ namespace memtrack {
|
||||||
|
|
||||||
void statistics() {
|
void statistics() {
|
||||||
#ifdef NO_IMPL
|
#ifdef NO_IMPL
|
||||||
logError("memtracker::statistics() does not work due compiler flags (NO_IMPL)");
|
logError(LOG_GENERAL, "memtracker::statistics() does not work due compiler flags (NO_IMPL)");
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
map<size_t, deque<void*>> objects;
|
map<size_t, deque<void*>> objects;
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace sql {
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncSqlPool::AsyncSqlPool(size_t threads) : _threads(new threads::ThreadPool(threads, "AsyncSqlPool")) {
|
AsyncSqlPool::AsyncSqlPool(size_t threads) : _threads(new threads::ThreadPool(threads, "AsyncSqlPool")) {
|
||||||
debugMessage("Created a new async thread pool!");
|
debugMessage(LOG_GENERAL, "Created a new async thread pool!");
|
||||||
}
|
}
|
||||||
AsyncSqlPool::~AsyncSqlPool() {
|
AsyncSqlPool::~AsyncSqlPool() {
|
||||||
delete _threads;
|
delete _threads;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <misc/lambda.h>
|
#include <misc/lambda.h>
|
||||||
|
|
||||||
#define ALLOW_STACK_ALLOCATION
|
#define ALLOW_STACK_ALLOCATION
|
||||||
#define LOG_SQL_CMD [](const sql::result &res){ if(!res) logCritical("Failed to execute sql command: " + std::to_string(res.code()) + "/" + res.msg() + " (" __FILE__ + ":" + to_string(__LINE__) + ")"); }
|
#define LOG_SQL_CMD [](const sql::result &res){ if(!res) logCritical(LOG_GENERAL, "Failed to execute sql command: " + std::to_string(res.code()) + "/" + res.msg() + " (" __FILE__ + ":" + to_string(__LINE__) + ")"); }
|
||||||
namespace sql {
|
namespace sql {
|
||||||
class result;
|
class result;
|
||||||
class SqlManager;
|
class SqlManager;
|
||||||
|
|
|
@ -380,7 +380,7 @@ std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &key_data, std
|
||||||
if(key_path.has_parent_path())
|
if(key_path.has_parent_path())
|
||||||
fs::create_directories(key_path.parent_path());
|
fs::create_directories(key_path.parent_path());
|
||||||
} catch (fs::filesystem_error& error) {
|
} catch (fs::filesystem_error& error) {
|
||||||
logError("Could not create key directory: " + string(error.what()));
|
logError(LOG_GENERAL, "Could not create key directory: " + string(error.what()));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue