config works

main
Brett 2025-03-07 18:40:43 -05:00
parent 66efccf095
commit 07a11656fa
7 changed files with 343 additions and 171 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) include(cmake/color.cmake)
set(BLT_VERSION 5.2.1) set(BLT_VERSION 5.2.2)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

View File

@ -99,7 +99,7 @@ namespace blt::fs
void write(const T& t) void write(const T& t)
{ {
static_assert(std::is_trivially_copyable_v<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> template <typename T>

View File

@ -25,181 +25,181 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <blt/logging/fmt_tokenizer.h> #include <blt/logging/fmt_tokenizer.h>
#include <blt/logging/logging_config.h>
#include <blt/meta/is_streamable.h> #include <blt/meta/is_streamable.h>
#include <blt/std/utility.h> #include <blt/std/utility.h>
namespace blt::logging namespace blt::logging
{ {
namespace detail namespace detail
{ {}
}
struct logger_t struct logger_t
{ {
explicit logger_t(std::ostream& stream): m_stream(stream) explicit logger_t(std::ostream& stream): m_stream(stream)
{ {}
}
template <typename... Args> template <typename... Args>
std::string log(std::string fmt, Args&&... args) std::string log(std::string fmt, Args&&... args)
{ {
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{}; auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
m_arg_print_funcs.clear(); m_arg_print_funcs.clear();
m_arg_print_funcs.resize(sizeof...(Args)); m_arg_print_funcs.resize(sizeof...(Args));
create_conv_funcs(sequence, std::forward<Args>(args)...); create_conv_funcs(sequence, std::forward<Args>(args)...);
compile(std::move(fmt)); compile(std::move(fmt));
process_strings(); process_strings();
return to_string(); return to_string();
} }
[[nodiscard]] std::string to_string() const; [[nodiscard]] std::string to_string() const;
private: private:
template <typename... Args, size_t... Indexes> template <typename... Args, size_t... Indexes>
void create_conv_funcs(std::integer_sequence<size_t, Indexes...>, Args&&... args) void create_conv_funcs(std::integer_sequence<size_t, Indexes...>, Args&&... args)
{ {
((handle_func<Indexes>(std::forward<Args>(args))), ...); ((handle_func<Indexes>(std::forward<Args>(args))), ...);
} }
template <size_t index, typename T> template <size_t index, typename T>
void handle_func(const T& t) void handle_func(const T& t)
{ {
m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type) m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type) {
{ switch (type.sign)
switch (type.sign) {
{ case fmt_sign_t::SPACE:
case fmt_sign_t::SPACE: if constexpr (std::is_arithmetic_v<T>)
if constexpr (std::is_arithmetic_v<T>) {
{ if (type.type != fmt_type_t::BINARY && static_cast<i64>(t) >= 0l)
if (type.type != fmt_type_t::BINARY && static_cast<i64>(t) >= 0l) stream << ' ';
stream << ' '; }
} break;
break; case fmt_sign_t::PLUS:
case fmt_sign_t::PLUS: case fmt_sign_t::MINUS:
case fmt_sign_t::MINUS: break;
break; }
} switch (type.type)
switch (type.type) {
{ case fmt_type_t::BINARY:
case fmt_type_t::BINARY: {
{ if constexpr (std::is_trivially_copyable_v<T>)
if constexpr (std::is_trivially_copyable_v<T>) {
{ // copy bytes of type
// copy bytes of type char buffer[sizeof(T)];
char buffer[sizeof(T)]; std::memcpy(buffer, &t, sizeof(T));
std::memcpy(buffer, &t, sizeof(T)); // display prefix
// display prefix if (type.alternate_form)
if (type.alternate_form) stream << '0' << (type.uppercase ? 'B' : 'b');
stream << '0' << (type.uppercase ? 'B' : 'b'); // print bytes
// print bytes for (size_t i = 0; i < sizeof(T); ++i)
for (size_t i = 0; i < sizeof(T); ++i) {
{ // print bits
// print bits for (size_t j = 0; j < 8; ++j)
for (size_t j = 0; j < 8; ++j) stream << ((buffer[i] & (1 << j)) ? '1' : '0');
stream << ((buffer[i] & (1 << j)) ? '1' : '0'); // special seperator defined via sign (weird hack, change?)
// special seperator defined via sign (weird hack, change?) if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1)
if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1) stream << ' ';
stream << ' '; }
} } else
} {
else if constexpr (blt::meta::is_streamable_v<T>)
{ stream << t;
if constexpr (blt::meta::is_streamable_v<T>) else
stream << t; stream << "{INVALID TYPE}";
else }
stream << "{INVALID TYPE}"; break;
} }
break; case fmt_type_t::CHAR:
} if constexpr (std::is_arithmetic_v<T> || std::is_convertible_v<T, char>)
case fmt_type_t::CHAR: {
if constexpr (std::is_arithmetic_v<T> || std::is_convertible_v<T, char>) stream << static_cast<char>(t);
{ } else
stream << static_cast<char>(t); {
} if constexpr (blt::meta::is_streamable_v<T>)
else stream << t;
{ else
if constexpr (blt::meta::is_streamable_v<T>) stream << "{INVALID TYPE}";
stream << t; }
else break;
stream << "{INVALID TYPE}"; case fmt_type_t::TYPE:
} stream << blt::type_string<T>();
break; break;
case fmt_type_t::TYPE: default:
stream << blt::type_string<T>(); handle_type(stream, type);
break; if constexpr (blt::meta::is_streamable_v<T>)
default: {
handle_type(stream, type); if constexpr (std::is_same_v<T, char> || std::is_same_v<T, signed char>)
if constexpr (blt::meta::is_streamable_v<T>) stream << static_cast<int>(t);
{ else if constexpr (std::is_same_v<T, unsigned char>)
if constexpr (std::is_same_v<T, char> || std::is_same_v<T, signed char>) stream << static_cast<unsigned int>(t);
stream << static_cast<int>(t); else
else if constexpr (std::is_same_v<T, unsigned char>) stream << t;
stream << static_cast<unsigned int>(t); } else
else stream << "{INVALID TYPE}";
stream << t; }
}else };
stream << "{INVALID TYPE}"; }
}
};
}
[[nodiscard]] size_t find_ending_brace(size_t begin) const; [[nodiscard]] size_t find_ending_brace(size_t begin) const;
void setup_stream(const fmt_spec_t& spec) const; void setup_stream(const fmt_spec_t& spec) const;
void process_strings(); void process_strings();
static void handle_type(std::ostream& stream, const fmt_spec_t& spec); static void handle_type(std::ostream& stream, const fmt_spec_t& spec);
static void exponential(std::ostream& stream); static void exponential(std::ostream& stream);
static void fixed(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::string m_fmt;
std::ostream& m_stream; std::ostream& m_stream;
fmt_parser_t m_parser{m_arg_print_funcs}; fmt_parser_t m_parser{m_arg_print_funcs};
// normal sections of string // normal sections of string
std::vector<std::string_view> m_string_sections; std::vector<std::string_view> m_string_sections;
// processed format specs // processed format specs
std::vector<fmt_spec_t> m_fmt_specs; std::vector<fmt_spec_t> m_fmt_specs;
std::vector<std::function<void(std::ostream&, const fmt_spec_t&)>> m_arg_print_funcs; 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_last_fmt_pos = 0;
size_t m_arg_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> logging_config_t& get_global_config();
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 set_thread_name(const std::string& name);
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> template <typename... Args>
void println(std::string fmt, Args&&... args) void print(std::string fmt, Args&&... args)
{ {
print(std::move(fmt), std::forward<Args>(args)...); auto& logger = get_global_logger();
newline(); print(logger.log(std::move(fmt), std::forward<Args>(args)...));
} }
template <typename... Args> template <typename... Args>
void println(std::ostream& stream, std::string fmt, Args&&... args) void print(std::ostream& stream, std::string fmt, Args&&... args)
{ {
print(stream, std::move(fmt), std::forward<Args>(args)...); auto& logger = get_global_logger();
stream << std::endl; 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 #endif // BLT_LOGGING_LOGGING_H

View File

@ -22,9 +22,9 @@
#include <array> #include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#include <blt/logging/logging.h>
#include <blt/std/types.h>
#include <blt/fs/fwddecl.h> #include <blt/fs/fwddecl.h>
#include <blt/logging/fwddecl.h>
#include <blt/std/types.h>
namespace blt::logging namespace blt::logging
{ {
@ -121,6 +121,79 @@ namespace blt::logging
friend logger_t; friend logger_t;
public: 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 // wrappers for streams exist in blt/fs/stream_wrappers.h
std::vector<fs::writer_t*> log_outputs = get_default_log_outputs(); std::vector<fs::writer_t*> log_outputs = get_default_log_outputs();
std::string log_format = get_default_log_format(); 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. // This creates output where the user message always starts at the same column.
bool ensure_alignment = true; bool ensure_alignment = true;
private:
static std::string get_default_log_format(); static std::string get_default_log_format();
static std::vector<fs::writer_t*> get_default_log_outputs(); static std::vector<fs::writer_t*> get_default_log_outputs();
static std::array<std::string, LOG_LEVEL_COUNT> get_default_log_level_colors(); static std::array<std::string, LOG_LEVEL_COUNT> get_default_log_level_colors();

View File

@ -17,19 +17,37 @@
*/ */
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <mutex>
#include <sstream> #include <sstream>
#include <thread>
#include <blt/iterator/enumerate.h> #include <blt/iterator/enumerate.h>
#include <blt/logging/logging.h> #include <blt/logging/logging.h>
#include <blt/std/hashmap.h>
#include <blt/std/types.h> #include <blt/std/types.h>
namespace blt::logging 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 struct logging_thread_context_t
{ {
std::stringstream stream; std::stringstream stream;
logger_t logger{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 std::string logger_t::to_string() const
{ {
return dynamic_cast<std::stringstream&>(m_stream).str(); return dynamic_cast<std::stringstream&>(m_stream).str();
@ -195,8 +213,7 @@ namespace blt::logging
logger_t& get_global_logger() logger_t& get_global_logger()
{ {
thread_local logging_thread_context_t context; return get_thread_context().logger;
return context.logger;
} }
void print(const std::string& str) void print(const std::string& str)
@ -208,4 +225,15 @@ namespace blt::logging
{ {
std::cout << std::endl; 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;
}
} }

View File

@ -52,7 +52,86 @@ namespace blt::logging
return map; 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() 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() std::array<std::string, LOG_LEVEL_COUNT> logging_config_t::get_default_log_level_names()
{ {
return { return {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",};
"TRACE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"FATAL",
};
} }
std::string logging_config_t::get_default_error_color() std::string logging_config_t::get_default_error_color()

View File

@ -160,10 +160,10 @@ int main()
std::ofstream os("test.txt"); std::ofstream os("test.txt");
blt::fs::fstream_writer_t wtr(os); 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 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(std::to_string(25));
writer.write(" with multiple types "); writer.write(" with multiple types ");
writer.write(std::to_string(34.23340)); writer.write(std::to_string(34.23340));