added logger
This commit is contained in:
+4
-2
@@ -57,7 +57,8 @@ set(UTILS_HEADER
|
||||
../include/matador/utils/os.hpp
|
||||
../include/matador/utils/access.hpp
|
||||
../include/matador/utils/identifier.hpp
|
||||
../include/matador/utils/cascade_type.hpp)
|
||||
../include/matador/utils/cascade_type.hpp
|
||||
../include/matador/utils/logger.hpp)
|
||||
|
||||
set(UTILS_SOURCES
|
||||
utils/field_attributes.cpp
|
||||
@@ -66,7 +67,8 @@ set(UTILS_SOURCES
|
||||
utils/library.cpp
|
||||
utils/os.cpp
|
||||
utils/identifier.cpp
|
||||
sql/value_extractor.cpp)
|
||||
sql/value_extractor.cpp
|
||||
utils/logger.cpp)
|
||||
|
||||
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
|
||||
target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace matador::sql {
|
||||
|
||||
connection::connection(connection_info info)
|
||||
: connection_info_(std::move(info))
|
||||
, logger_(stdout, "SQL")
|
||||
{
|
||||
connection_.reset(backend_provider::instance().create_connection(connection_info_.type, connection_info_));
|
||||
}
|
||||
@@ -20,6 +21,7 @@ connection::connection(const std::string& dns)
|
||||
|
||||
connection::connection(const connection &x)
|
||||
: connection_info_(x.connection_info_)
|
||||
, logger_(x.logger_)
|
||||
{
|
||||
if (x.connection_) {
|
||||
throw std::runtime_error("couldn't copy connection with valid connection impl");
|
||||
@@ -28,6 +30,7 @@ connection::connection(const connection &x)
|
||||
|
||||
connection &connection::operator=(const connection &x) {
|
||||
connection_info_ = x.connection_info_;
|
||||
logger_ = x.logger_;
|
||||
if (x.connection_) {
|
||||
throw std::runtime_error("couldn't copy connection with valid connection impl");
|
||||
}
|
||||
@@ -75,11 +78,13 @@ bool connection::exists(const std::string &table_name) const
|
||||
|
||||
std::pair<size_t, std::string> connection::execute(const std::string &sql) const
|
||||
{
|
||||
logger_.debug(sql);
|
||||
return {connection_->execute(sql), sql};
|
||||
}
|
||||
|
||||
std::unique_ptr<query_result_impl> connection::call_fetch(const std::string &sql) const
|
||||
std::unique_ptr<query_result_impl> connection::fetch(const std::string &sql) const
|
||||
{
|
||||
logger_.debug(sql);
|
||||
return connection_->fetch(sql);
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -37,11 +37,14 @@ const std::string &dialect::data_type_at(data_type_t type) const
|
||||
std::string dialect::prepare_identifier(const column &col) const
|
||||
{
|
||||
std::string result(col.name());
|
||||
escape_quotes_in_identifier(result);
|
||||
if (!col.is_function()) {
|
||||
escape_quotes_in_identifier(result);
|
||||
quote_identifier(result);
|
||||
} else {
|
||||
return sql_func_map_.at(col.function()) + "(" + result + ")";
|
||||
result = sql_func_map_.at(col.function()) + "(" + result + ")";
|
||||
}
|
||||
if (!col.alias().empty()) {
|
||||
result += " AS " + col.alias();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -460,4 +460,9 @@ column count(const std::string &column)
|
||||
return {sql_function_t::COUNT, column};
|
||||
}
|
||||
|
||||
column count_all()
|
||||
{
|
||||
return count("*");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@ record query_select_finish::fetch_one()
|
||||
|
||||
std::unique_ptr<query_result_impl> query_select_finish::fetch()
|
||||
{
|
||||
return session_.call_fetch(builder_.compile().sql);
|
||||
return session_.fetch(builder_.compile().sql);
|
||||
}
|
||||
|
||||
query_intermediate::query_intermediate(session &db, query_builder &query)
|
||||
|
||||
+3
-3
@@ -56,7 +56,7 @@ query_result<record> session::fetch(const query &q) const
|
||||
const_cast<column&>(col).type(rit->type());
|
||||
}
|
||||
}
|
||||
auto res = c->call_fetch(q.sql);
|
||||
auto res = c->fetch(q.sql);
|
||||
return query_result<record>{std::move(res), q.prototype};
|
||||
}
|
||||
|
||||
@@ -83,13 +83,13 @@ const class dialect &session::dialect() const
|
||||
return dialect_;
|
||||
}
|
||||
|
||||
std::unique_ptr<query_result_impl> session::call_fetch(const std::string &sql) const
|
||||
std::unique_ptr<query_result_impl> session::fetch(const std::string &sql) const
|
||||
{
|
||||
auto c = pool_.acquire();
|
||||
if (!c.valid()) {
|
||||
throw std::logic_error("no database connection available");
|
||||
}
|
||||
return c->call_fetch(sql);
|
||||
return c->fetch(sql);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#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];
|
||||
}
|
||||
|
||||
}
|
||||
+161
-2
@@ -1,13 +1,28 @@
|
||||
#include "matador/utils/os.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace matador::utils::os {
|
||||
|
||||
#ifdef _WIN32
|
||||
char DIR_SEPARATOR = '\\';
|
||||
const char* DIR_SEPARATOR_STRING = "\\";
|
||||
#else
|
||||
char DIR_SEPARATOR = '/';
|
||||
const char* DIR_SEPARATOR_STRING = "/";
|
||||
#endif
|
||||
|
||||
std::string getenv(const char *name) {
|
||||
#ifdef _WIN32
|
||||
char var[1024];
|
||||
@@ -46,4 +61,148 @@ std::string error_string(unsigned long error) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string get_current_dir()
|
||||
{
|
||||
char buffer[1024];
|
||||
#ifdef _WIN32
|
||||
char *dir = _getcwd(buffer, 1024);
|
||||
#else
|
||||
char *dir = ::getcwd(buffer, 1024);
|
||||
#endif
|
||||
if (dir == nullptr) {
|
||||
#ifdef _WIN32
|
||||
::strerror_s(buffer, 1023, errno);
|
||||
throw std::logic_error(buffer);
|
||||
#else
|
||||
throw std::logic_error(::strerror(errno));
|
||||
#endif
|
||||
}
|
||||
return {buffer};
|
||||
}
|
||||
|
||||
FILE* fopen(const std::string &path, const char *modes)
|
||||
{
|
||||
return fopen(path.c_str(), modes);
|
||||
}
|
||||
|
||||
FILE* fopen(const char *path, const char *modes)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _fsopen(path, modes, _SH_DENYWR);
|
||||
#else
|
||||
return ::fopen(path, modes);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mkdir(const std::string &dirname)
|
||||
{
|
||||
return os::mkdir(dirname.c_str());
|
||||
}
|
||||
|
||||
bool mkdir(const char *dirname)
|
||||
{
|
||||
if (dirname == nullptr || strlen(dirname) == 0) {
|
||||
return true;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
return ::_mkdir(dirname) == 0;
|
||||
#else
|
||||
return ::mkdir(dirname, S_IRWXU) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool chdir(const std::string &dirname)
|
||||
{
|
||||
return os::chdir(dirname.c_str());
|
||||
}
|
||||
|
||||
bool chdir(const char *dirname)
|
||||
{
|
||||
if (dirname == nullptr || strlen(dirname) == 0) {
|
||||
return true;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
return _chdir(dirname) == 0;
|
||||
#else
|
||||
return ::chdir(dirname) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rmdir(const std::string &dirname)
|
||||
{
|
||||
return os::rmdir(dirname.c_str());
|
||||
}
|
||||
|
||||
bool rmdir(const char *dirname)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _rmdir(dirname) == 0;
|
||||
#else
|
||||
return ::rmdir(dirname) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mkpath(const std::string &path) {
|
||||
return os::rmpath(path.c_str());
|
||||
}
|
||||
|
||||
bool mkpath(const char *path) {
|
||||
char tmp[256];
|
||||
size_t len;
|
||||
|
||||
snprintf(tmp, sizeof(tmp),"%s",path);
|
||||
len = strlen(tmp);
|
||||
if (len == 0) {
|
||||
return true;
|
||||
}
|
||||
if(tmp[len - 1] == DIR_SEPARATOR) {
|
||||
tmp[len - 1] = 0;
|
||||
}
|
||||
for(char *p = tmp + 1; *p; p++) {
|
||||
if (*p == DIR_SEPARATOR) {
|
||||
*p = 0;
|
||||
if (!os::mkdir(tmp)) {
|
||||
return false;
|
||||
}
|
||||
*p = DIR_SEPARATOR;
|
||||
}
|
||||
}
|
||||
return os::mkdir(tmp);
|
||||
}
|
||||
|
||||
bool rmpath(const std::string &path)
|
||||
{
|
||||
return os::rmpath(path.c_str());
|
||||
}
|
||||
|
||||
bool rmpath(const char *path)
|
||||
{
|
||||
// change next to last path segment
|
||||
std::vector<char> pathcopy(path, path+::strlen(path)+1);
|
||||
std::vector<std::string> segments;
|
||||
#ifdef _WIN32
|
||||
char *next_token = nullptr;
|
||||
char *segment = ::strtok_s(pathcopy.data(), DIR_SEPARATOR_STRING, &next_token);
|
||||
#else
|
||||
char *segment = ::strtok(pathcopy.data(), DIR_SEPARATOR_STRING);
|
||||
#endif
|
||||
|
||||
while (segment != nullptr) {
|
||||
os::chdir(segment);
|
||||
segments.emplace_back(segment);
|
||||
#ifdef _WIN32
|
||||
segment = ::strtok_s(nullptr, DIR_SEPARATOR_STRING, &next_token);
|
||||
#else
|
||||
segment = ::strtok(nullptr, DIR_SEPARATOR_STRING);
|
||||
#endif
|
||||
}
|
||||
|
||||
auto first = segments.rbegin();
|
||||
for (auto it=first; it!=segments.rend(); ++it) {
|
||||
os::chdir("..");
|
||||
os::rmdir(*it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "matador/utils/string.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
void replace_all(std::string &in, const std::string &from, const std::string &to)
|
||||
@@ -19,4 +21,14 @@ const std::string &to_string(const std::string &str)
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t split(const std::string &str, char delim, std::vector<std::string> &values)
|
||||
{
|
||||
std::stringstream ss(str);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
values.push_back(item);
|
||||
}
|
||||
return values.size();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user