query/src/utils/logger.cpp

149 lines
3.7 KiB
C++

#include "matador/utils/logger.hpp"
#include "matador/utils/os.hpp"
#include "matador/utils/string.hpp"
#include <chrono>
#include <cstring>
#include <map>
#include <stdexcept>
#include <thread>
#include <utility>
#include <vector>
namespace matador::utils {
std::size_t acquire_thread_index(std::thread::id id);
std::map<log_level, std::string> level_strings = { /* NOLINT */
{ log_level::LVL_DEBUG, "DEBUG" },
{ log_level::LVL_INFO, "INFO" },
{ log_level::LVL_WARN, "WARN" },
{ log_level::LVL_ERROR, "ERROR" },
{ log_level::LVL_TRACE, "TRACE" }
};
logger::logger(const std::string &path, std::string source)
: source_(std::move(source))
{
std::string filename(path);
// find last dir delimiter
const char *last = strrchr(path.c_str(), os::DIR_SEPARATOR);
if (last != nullptr) {
path_.assign(path.data(), last-path.data());
} else {
path_.clear();
}
if (last != nullptr) {
filename = (last + 1);
}
// extract base path and extension
std::vector<std::string> result;
if (utils::split(filename, '.', result) != 2) {
throw std::logic_error("split path must consists of two elements");
}
// get current path
auto pwd = os::get_current_dir();
// make path
os::mkpath(path_);
// change into path
os::chdir(path_);
// create file
stream = os::fopen(filename, "a");
if (stream == nullptr) {
os::chdir(pwd);
throw std::logic_error("error opening file");
}
os::chdir(pwd);
}
logger::logger(FILE *file, std::string source)
: stream(file)
, source_(std::move(source))
{}
logger::logger(const logger &x)
: path_(x.path_)
, stream(x.stream)
, source_(x.source_)
{}
logger &logger::operator=(const logger &x)
{
if (this == &x) {
return *this;
}
path_ = x.path_;
stream = x.stream;
source_ = x.source_;
return *this;
}
logger::logger(logger &&x) noexcept
: path_(std::move(x.path_))
, stream(x.stream)
, source_(std::move(x.source_))
{
x.stream = nullptr;
}
logger &logger::operator=(logger &&x) noexcept
{
path_ = std::move(x.path_);
std::swap(stream, x.stream);
source_ = std::move(x.source_);
return *this;
}
void logger::log(log_level lvl, const char *message) const
{
using namespace std::chrono;
auto timestamp = system_clock::now();
auto coarse = system_clock::to_time_t(timestamp);
auto fine = time_point_cast<std::chrono::milliseconds>(timestamp);
char timestamp_buffer[sizeof "9999-12-31 23:59:59.999"];
std::snprintf(timestamp_buffer + std::strftime(timestamp_buffer,
sizeof timestamp_buffer - 3,
"%F %T.",
std::localtime(&coarse)), 4, "%03ld", fine.time_since_epoch().count() % 1000);
char buffer[1024];
#ifdef _MSC_VER
int ret = sprintf_s(buffer, 1024, "%s [Thread %zu] [%-7s] [%s]: %s\n", timestamp_buffer, acquire_thread_index(std::this_thread::get_id()), level_strings[lvl].c_str(), source_.c_str(), message);
#else
int ret = sprintf(buffer, "%s [Thread %lu] [%-7s] [%s]: %s\n", timestamp_buffer, acquire_thread_index(std::this_thread::get_id()), level_strings[lvl].c_str(), source_.c_str(), message);
#endif
std::lock_guard<std::mutex> l(mutex_);
write(buffer, ret);
}
void logger::write(const char *message, size_t size) const
{
fwrite(message, sizeof(char), size, stream);
fflush(stream);
}
void logger::close()
{
if (stream) {
fclose(stream);
stream = nullptr;
}
}
std::size_t acquire_thread_index(std::thread::id id)
{
static std::size_t next_index = 0;
static std::mutex my_mutex;
static std::map<std::thread::id, std::size_t> ids;
std::lock_guard<std::mutex> lock(my_mutex);
if(ids.find(id) == ids.end()) {
ids[id] = next_index++;
}
return ids[id];
}
}