config works
parent
66efccf095
commit
07a11656fa
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
include(cmake/color.cmake)
|
||||
set(BLT_VERSION 5.2.1)
|
||||
set(BLT_VERSION 5.2.2)
|
||||
|
||||
set(BLT_TARGET BLT)
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace blt::fs
|
|||
void write(const T& t)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
m_writer->write(reinterpret_cast<char*>(&t), sizeof(T));
|
||||
m_writer->write(reinterpret_cast<const char*>(&t), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -25,181 +25,181 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <blt/logging/fmt_tokenizer.h>
|
||||
#include <blt/logging/logging_config.h>
|
||||
#include <blt/meta/is_streamable.h>
|
||||
#include <blt/std/utility.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
}
|
||||
namespace detail
|
||||
{}
|
||||
|
||||
struct logger_t
|
||||
{
|
||||
explicit logger_t(std::ostream& stream): m_stream(stream)
|
||||
{
|
||||
}
|
||||
struct logger_t
|
||||
{
|
||||
explicit logger_t(std::ostream& stream): m_stream(stream)
|
||||
{}
|
||||
|
||||
template <typename... Args>
|
||||
std::string log(std::string fmt, Args&&... args)
|
||||
{
|
||||
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
|
||||
m_arg_print_funcs.clear();
|
||||
m_arg_print_funcs.resize(sizeof...(Args));
|
||||
create_conv_funcs(sequence, std::forward<Args>(args)...);
|
||||
compile(std::move(fmt));
|
||||
process_strings();
|
||||
return to_string();
|
||||
}
|
||||
template <typename... Args>
|
||||
std::string log(std::string fmt, Args&&... args)
|
||||
{
|
||||
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
|
||||
m_arg_print_funcs.clear();
|
||||
m_arg_print_funcs.resize(sizeof...(Args));
|
||||
create_conv_funcs(sequence, std::forward<Args>(args)...);
|
||||
compile(std::move(fmt));
|
||||
process_strings();
|
||||
return to_string();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string to_string() const;
|
||||
[[nodiscard]] std::string to_string() const;
|
||||
|
||||
private:
|
||||
template <typename... Args, size_t... Indexes>
|
||||
void create_conv_funcs(std::integer_sequence<size_t, Indexes...>, Args&&... args)
|
||||
{
|
||||
((handle_func<Indexes>(std::forward<Args>(args))), ...);
|
||||
}
|
||||
private:
|
||||
template <typename... Args, size_t... Indexes>
|
||||
void create_conv_funcs(std::integer_sequence<size_t, Indexes...>, Args&&... args)
|
||||
{
|
||||
((handle_func<Indexes>(std::forward<Args>(args))), ...);
|
||||
}
|
||||
|
||||
template <size_t index, typename T>
|
||||
void handle_func(const T& t)
|
||||
{
|
||||
m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type)
|
||||
{
|
||||
switch (type.sign)
|
||||
{
|
||||
case fmt_sign_t::SPACE:
|
||||
if constexpr (std::is_arithmetic_v<T>)
|
||||
{
|
||||
if (type.type != fmt_type_t::BINARY && static_cast<i64>(t) >= 0l)
|
||||
stream << ' ';
|
||||
}
|
||||
break;
|
||||
case fmt_sign_t::PLUS:
|
||||
case fmt_sign_t::MINUS:
|
||||
break;
|
||||
}
|
||||
switch (type.type)
|
||||
{
|
||||
case fmt_type_t::BINARY:
|
||||
{
|
||||
if constexpr (std::is_trivially_copyable_v<T>)
|
||||
{
|
||||
// copy bytes of type
|
||||
char buffer[sizeof(T)];
|
||||
std::memcpy(buffer, &t, sizeof(T));
|
||||
// display prefix
|
||||
if (type.alternate_form)
|
||||
stream << '0' << (type.uppercase ? 'B' : 'b');
|
||||
// print bytes
|
||||
for (size_t i = 0; i < sizeof(T); ++i)
|
||||
{
|
||||
// print bits
|
||||
for (size_t j = 0; j < 8; ++j)
|
||||
stream << ((buffer[i] & (1 << j)) ? '1' : '0');
|
||||
// special seperator defined via sign (weird hack, change?)
|
||||
if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1)
|
||||
stream << ' ';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (blt::meta::is_streamable_v<T>)
|
||||
stream << t;
|
||||
else
|
||||
stream << "{INVALID TYPE}";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case fmt_type_t::CHAR:
|
||||
if constexpr (std::is_arithmetic_v<T> || std::is_convertible_v<T, char>)
|
||||
{
|
||||
stream << static_cast<char>(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (blt::meta::is_streamable_v<T>)
|
||||
stream << t;
|
||||
else
|
||||
stream << "{INVALID TYPE}";
|
||||
}
|
||||
break;
|
||||
case fmt_type_t::TYPE:
|
||||
stream << blt::type_string<T>();
|
||||
break;
|
||||
default:
|
||||
handle_type(stream, type);
|
||||
if constexpr (blt::meta::is_streamable_v<T>)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, char> || std::is_same_v<T, signed char>)
|
||||
stream << static_cast<int>(t);
|
||||
else if constexpr (std::is_same_v<T, unsigned char>)
|
||||
stream << static_cast<unsigned int>(t);
|
||||
else
|
||||
stream << t;
|
||||
}else
|
||||
stream << "{INVALID TYPE}";
|
||||
}
|
||||
};
|
||||
}
|
||||
template <size_t index, typename T>
|
||||
void handle_func(const T& t)
|
||||
{
|
||||
m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type) {
|
||||
switch (type.sign)
|
||||
{
|
||||
case fmt_sign_t::SPACE:
|
||||
if constexpr (std::is_arithmetic_v<T>)
|
||||
{
|
||||
if (type.type != fmt_type_t::BINARY && static_cast<i64>(t) >= 0l)
|
||||
stream << ' ';
|
||||
}
|
||||
break;
|
||||
case fmt_sign_t::PLUS:
|
||||
case fmt_sign_t::MINUS:
|
||||
break;
|
||||
}
|
||||
switch (type.type)
|
||||
{
|
||||
case fmt_type_t::BINARY:
|
||||
{
|
||||
if constexpr (std::is_trivially_copyable_v<T>)
|
||||
{
|
||||
// copy bytes of type
|
||||
char buffer[sizeof(T)];
|
||||
std::memcpy(buffer, &t, sizeof(T));
|
||||
// display prefix
|
||||
if (type.alternate_form)
|
||||
stream << '0' << (type.uppercase ? 'B' : 'b');
|
||||
// print bytes
|
||||
for (size_t i = 0; i < sizeof(T); ++i)
|
||||
{
|
||||
// print bits
|
||||
for (size_t j = 0; j < 8; ++j)
|
||||
stream << ((buffer[i] & (1 << j)) ? '1' : '0');
|
||||
// special seperator defined via sign (weird hack, change?)
|
||||
if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1)
|
||||
stream << ' ';
|
||||
}
|
||||
} else
|
||||
{
|
||||
if constexpr (blt::meta::is_streamable_v<T>)
|
||||
stream << t;
|
||||
else
|
||||
stream << "{INVALID TYPE}";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case fmt_type_t::CHAR:
|
||||
if constexpr (std::is_arithmetic_v<T> || std::is_convertible_v<T, char>)
|
||||
{
|
||||
stream << static_cast<char>(t);
|
||||
} else
|
||||
{
|
||||
if constexpr (blt::meta::is_streamable_v<T>)
|
||||
stream << t;
|
||||
else
|
||||
stream << "{INVALID TYPE}";
|
||||
}
|
||||
break;
|
||||
case fmt_type_t::TYPE:
|
||||
stream << blt::type_string<T>();
|
||||
break;
|
||||
default:
|
||||
handle_type(stream, type);
|
||||
if constexpr (blt::meta::is_streamable_v<T>)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, char> || std::is_same_v<T, signed char>)
|
||||
stream << static_cast<int>(t);
|
||||
else if constexpr (std::is_same_v<T, unsigned char>)
|
||||
stream << static_cast<unsigned int>(t);
|
||||
else
|
||||
stream << t;
|
||||
} else
|
||||
stream << "{INVALID TYPE}";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t find_ending_brace(size_t begin) const;
|
||||
void setup_stream(const fmt_spec_t& spec) const;
|
||||
void process_strings();
|
||||
static void handle_type(std::ostream& stream, const fmt_spec_t& spec);
|
||||
[[nodiscard]] size_t find_ending_brace(size_t begin) const;
|
||||
void setup_stream(const fmt_spec_t& spec) const;
|
||||
void process_strings();
|
||||
static void handle_type(std::ostream& stream, const fmt_spec_t& spec);
|
||||
|
||||
static void exponential(std::ostream& stream);
|
||||
static void fixed(std::ostream& stream);
|
||||
static void exponential(std::ostream& stream);
|
||||
static void fixed(std::ostream& stream);
|
||||
|
||||
void compile(std::string fmt);
|
||||
void compile(std::string fmt);
|
||||
|
||||
std::optional<std::pair<size_t, size_t>> consume_to_next_fmt();
|
||||
std::optional<std::pair<size_t, size_t>> consume_to_next_fmt();
|
||||
|
||||
std::string m_fmt;
|
||||
std::ostream& m_stream;
|
||||
fmt_parser_t m_parser{m_arg_print_funcs};
|
||||
// normal sections of string
|
||||
std::vector<std::string_view> m_string_sections;
|
||||
// processed format specs
|
||||
std::vector<fmt_spec_t> m_fmt_specs;
|
||||
std::vector<std::function<void(std::ostream&, const fmt_spec_t&)>> m_arg_print_funcs;
|
||||
size_t m_last_fmt_pos = 0;
|
||||
size_t m_arg_pos = 0;
|
||||
};
|
||||
std::string m_fmt;
|
||||
std::ostream& m_stream;
|
||||
fmt_parser_t m_parser{m_arg_print_funcs};
|
||||
// normal sections of string
|
||||
std::vector<std::string_view> m_string_sections;
|
||||
// processed format specs
|
||||
std::vector<fmt_spec_t> m_fmt_specs;
|
||||
std::vector<std::function<void(std::ostream&, const fmt_spec_t&)>> m_arg_print_funcs;
|
||||
size_t m_last_fmt_pos = 0;
|
||||
size_t m_arg_pos = 0;
|
||||
};
|
||||
|
||||
void print(const std::string& str);
|
||||
void print(const std::string& str);
|
||||
|
||||
void newline();
|
||||
void newline();
|
||||
|
||||
logger_t& get_global_logger();
|
||||
logger_t& get_global_logger();
|
||||
|
||||
template <typename... Args>
|
||||
void print(std::string fmt, Args&&... args)
|
||||
{
|
||||
auto& logger = get_global_logger();
|
||||
print(logger.log(std::move(fmt), std::forward<Args>(args)...));
|
||||
}
|
||||
logging_config_t& get_global_config();
|
||||
|
||||
template <typename... Args>
|
||||
void print(std::ostream& stream, std::string fmt, Args&&... args)
|
||||
{
|
||||
auto& logger = get_global_logger();
|
||||
stream << logger.log(std::move(fmt), std::forward<Args>(args)...);
|
||||
}
|
||||
void set_thread_name(const std::string& name);
|
||||
|
||||
template <typename... Args>
|
||||
void println(std::string fmt, Args&&... args)
|
||||
{
|
||||
print(std::move(fmt), std::forward<Args>(args)...);
|
||||
newline();
|
||||
}
|
||||
template <typename... Args>
|
||||
void print(std::string fmt, Args&&... args)
|
||||
{
|
||||
auto& logger = get_global_logger();
|
||||
print(logger.log(std::move(fmt), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void println(std::ostream& stream, std::string fmt, Args&&... args)
|
||||
{
|
||||
print(stream, std::move(fmt), std::forward<Args>(args)...);
|
||||
stream << std::endl;
|
||||
}
|
||||
template <typename... Args>
|
||||
void print(std::ostream& stream, std::string fmt, Args&&... args)
|
||||
{
|
||||
auto& logger = get_global_logger();
|
||||
stream << logger.log(std::move(fmt), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void println(std::string fmt, Args&&... args)
|
||||
{
|
||||
print(std::move(fmt), std::forward<Args>(args)...);
|
||||
newline();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void println(std::ostream& stream, std::string fmt, Args&&... args)
|
||||
{
|
||||
print(stream, std::move(fmt), std::forward<Args>(args)...);
|
||||
stream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BLT_LOGGING_LOGGING_H
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <blt/logging/logging.h>
|
||||
#include <blt/std/types.h>
|
||||
#include <blt/fs/fwddecl.h>
|
||||
#include <blt/logging/fwddecl.h>
|
||||
#include <blt/std/types.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
|
@ -121,6 +121,79 @@ namespace blt::logging
|
|||
friend logger_t;
|
||||
|
||||
public:
|
||||
logging_config_t()
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
void compile();
|
||||
|
||||
logging_config_t& add_log_output(fs::writer_t* writer)
|
||||
{
|
||||
log_outputs.push_back(writer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_log_format(std::string format)
|
||||
{
|
||||
log_format = std::move(format);
|
||||
compile();
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_error_color(std::string color)
|
||||
{
|
||||
error_color = std::move(color);
|
||||
compile();
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_log_level_colors(std::array<std::string, LOG_LEVEL_COUNT> colors)
|
||||
{
|
||||
log_level_colors = std::move(colors);
|
||||
compile();
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_log_level_names(std::array<std::string, LOG_LEVEL_COUNT> names)
|
||||
{
|
||||
log_level_names = std::move(names);
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_level(const log_level_t level)
|
||||
{
|
||||
this->level = level;
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_use_color(const bool use_color)
|
||||
{
|
||||
this->use_color = use_color;
|
||||
compile();
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_print_full_name(const bool print_full_name)
|
||||
{
|
||||
this->print_full_name = print_full_name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_ensure_alignment(const bool ensure_alignment)
|
||||
{
|
||||
this->ensure_alignment = ensure_alignment;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::pair<const std::vector<tags::detail::log_tag_token_t>&, const std::vector<std::string>&> get_log_tag_tokens() const
|
||||
{
|
||||
return {log_tag_tokens, log_tag_content};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> log_tag_content;
|
||||
std::vector<tags::detail::log_tag_token_t> log_tag_tokens;
|
||||
// wrappers for streams exist in blt/fs/stream_wrappers.h
|
||||
std::vector<fs::writer_t*> log_outputs = get_default_log_outputs();
|
||||
std::string log_format = get_default_log_format();
|
||||
|
@ -135,7 +208,6 @@ namespace blt::logging
|
|||
// This creates output where the user message always starts at the same column.
|
||||
bool ensure_alignment = true;
|
||||
|
||||
private:
|
||||
static std::string get_default_log_format();
|
||||
static std::vector<fs::writer_t*> get_default_log_outputs();
|
||||
static std::array<std::string, LOG_LEVEL_COUNT> get_default_log_level_colors();
|
||||
|
|
|
@ -17,19 +17,37 @@
|
|||
*/
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <blt/iterator/enumerate.h>
|
||||
#include <blt/logging/logging.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <blt/std/types.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
struct global_context_t
|
||||
{
|
||||
logging_config_t global_config;
|
||||
std::mutex thread_name_mutex;
|
||||
hashmap_t<std::thread::id, std::string> thread_names;
|
||||
};
|
||||
|
||||
static global_context_t global_context;
|
||||
|
||||
struct logging_thread_context_t
|
||||
{
|
||||
std::stringstream stream;
|
||||
logger_t logger{stream};
|
||||
};
|
||||
|
||||
logging_thread_context_t& get_thread_context()
|
||||
{
|
||||
thread_local logging_thread_context_t context;
|
||||
return context;
|
||||
}
|
||||
|
||||
std::string logger_t::to_string() const
|
||||
{
|
||||
return dynamic_cast<std::stringstream&>(m_stream).str();
|
||||
|
@ -195,8 +213,7 @@ namespace blt::logging
|
|||
|
||||
logger_t& get_global_logger()
|
||||
{
|
||||
thread_local logging_thread_context_t context;
|
||||
return context.logger;
|
||||
return get_thread_context().logger;
|
||||
}
|
||||
|
||||
void print(const std::string& str)
|
||||
|
@ -208,4 +225,15 @@ namespace blt::logging
|
|||
{
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
logging_config_t& get_global_config()
|
||||
{
|
||||
return global_context.global_config;
|
||||
}
|
||||
|
||||
void set_thread_name(const std::string& name)
|
||||
{
|
||||
std::scoped_lock lock{global_context.thread_name_mutex};
|
||||
global_context.thread_names[std::this_thread::get_id()] = name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,86 @@ namespace blt::logging
|
|||
return map;
|
||||
}
|
||||
|
||||
hashmap_t<std::string_view, log_tag_token_t> tag_map = make_map();
|
||||
std::array<bool, static_cast<u8>(log_tag_token_t::CONTENT)> tag_known_values{
|
||||
// year
|
||||
false,
|
||||
// month
|
||||
false,
|
||||
// day
|
||||
false,
|
||||
// hour
|
||||
false,
|
||||
// minute
|
||||
false,
|
||||
// second
|
||||
false,
|
||||
// ms
|
||||
false,
|
||||
// ns
|
||||
false,
|
||||
// unix
|
||||
false,
|
||||
// iso year
|
||||
false,
|
||||
// time
|
||||
false,
|
||||
// full_time
|
||||
false,
|
||||
// lc
|
||||
true,
|
||||
// ec
|
||||
true,
|
||||
// conditional error
|
||||
false,
|
||||
// reset
|
||||
true,
|
||||
// log level
|
||||
false,
|
||||
// thread_name
|
||||
false,
|
||||
// file
|
||||
false,
|
||||
// line
|
||||
false,
|
||||
// str
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
void logging_config_t::compile()
|
||||
{
|
||||
static hashmap_t<std::string_view, tags::detail::log_tag_token_t> tag_map = tags::detail::make_map();
|
||||
log_tag_content.clear();
|
||||
log_tag_tokens.clear();
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < log_format.size(); ++i)
|
||||
{
|
||||
size_t start = i;
|
||||
while (i < log_format.size() && log_format[i] != '{')
|
||||
++i;
|
||||
if (i == log_format.size() || (i < log_format.size() && (i - start) > 0))
|
||||
{
|
||||
log_tag_content.emplace_back(std::string_view(log_format.data() + start, i - start));
|
||||
log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT);
|
||||
if (i == log_format.size())
|
||||
break;
|
||||
}
|
||||
start = i;
|
||||
while (i < log_format.size() && log_format[i] != '}')
|
||||
++i;
|
||||
const auto tag = std::string_view(log_format.data() + start, i - start + 1);
|
||||
auto it = tag_map.find(tag);
|
||||
if (it == tag_map.end())
|
||||
throw std::runtime_error("Invalid log tag: " + std::string(tag));
|
||||
log_tag_tokens.emplace_back(it->second);
|
||||
}
|
||||
|
||||
if (i < log_format.size())
|
||||
{
|
||||
log_tag_content.emplace_back(std::string_view(log_format.data() + i, log_format.size() - i));
|
||||
log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
std::string logging_config_t::get_default_log_format()
|
||||
|
@ -90,14 +169,7 @@ namespace blt::logging
|
|||
|
||||
std::array<std::string, LOG_LEVEL_COUNT> logging_config_t::get_default_log_level_names()
|
||||
{
|
||||
return {
|
||||
"TRACE",
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"WARN",
|
||||
"ERROR",
|
||||
"FATAL",
|
||||
};
|
||||
return {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",};
|
||||
}
|
||||
|
||||
std::string logging_config_t::get_default_error_color()
|
||||
|
|
|
@ -160,10 +160,10 @@ int main()
|
|||
|
||||
std::ofstream os("test.txt");
|
||||
blt::fs::fstream_writer_t wtr(os);
|
||||
blt::fs::writer_wrapper_t writer(wtr);
|
||||
blt::fs::writer_string_wrapper_t writer(wtr);
|
||||
|
||||
writer.write("This is a println with a stream\n");
|
||||
writer.write("This is a mixed print");
|
||||
writer.write("This is a mixed print ");
|
||||
writer.write(std::to_string(25));
|
||||
writer.write(" with multiple types ");
|
||||
writer.write(std::to_string(34.23340));
|
||||
|
|
Loading…
Reference in New Issue