149 lines
3.7 KiB
C++
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];
|
|
}
|
|
|
|
} |