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)
include(cmake/color.cmake)
set(BLT_VERSION 5.2.1)
set(BLT_VERSION 5.2.2)
set(BLT_TARGET BLT)

View File

@ -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>

View File

@ -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

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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()

View File

@ -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));