i think logging is working. need to make macros and test
parent
07a11656fa
commit
60536fd602
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
include(cmake/color.cmake)
|
||||
set(BLT_VERSION 5.2.2)
|
||||
set(BLT_VERSION 5.2.3)
|
||||
|
||||
set(BLT_TARGET BLT)
|
||||
|
||||
|
|
|
@ -31,9 +31,6 @@
|
|||
|
||||
namespace blt::logging
|
||||
{
|
||||
namespace detail
|
||||
{}
|
||||
|
||||
struct logger_t
|
||||
{
|
||||
explicit logger_t(std::ostream& stream): m_stream(stream)
|
||||
|
@ -173,6 +170,8 @@ namespace blt::logging
|
|||
|
||||
void set_thread_name(const std::string& name);
|
||||
|
||||
const std::string& get_thread_name();
|
||||
|
||||
template <typename... Args>
|
||||
void print(std::string fmt, Args&&... args)
|
||||
{
|
||||
|
@ -200,6 +199,22 @@ namespace blt::logging
|
|||
print(stream, std::move(fmt), std::forward<Args>(args)...);
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log(log_level_t level, const char* file, const i32 line, std::string fmt, Args&&... args)
|
||||
{
|
||||
auto& logger = get_global_logger();
|
||||
auto& config = get_global_config();
|
||||
auto user_str = logger.log(std::move(fmt), std::forward<Args>(args)...);
|
||||
auto log_fmt_str = config.generate(user_str, get_thread_name(), level, file, line);
|
||||
if (log_fmt_str)
|
||||
print(std::move(*log_fmt_str));
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{}
|
||||
}
|
||||
|
||||
#define BLT_LOG(level, fmt, ...) blt::logging::log(level, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif // BLT_LOGGING_LOGGING_H
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define BLT_LOGGING_LOGGING_CONFIG_H
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <blt/fs/fwddecl.h>
|
||||
|
@ -44,10 +45,12 @@ namespace blt::logging
|
|||
inline constexpr auto SECOND = "{SECOND}";
|
||||
// Current Millisecond
|
||||
inline constexpr auto MILLISECOND = "{MS}";
|
||||
// Current Nanosecond time, This is direct output of nanotime
|
||||
// Current Nanosecond
|
||||
inline constexpr auto NANOSECOND = "{NS}";
|
||||
// Current Unix time in milliseconds
|
||||
inline constexpr auto UNIX_TIME = "{UNIX}";
|
||||
// Current Unix time in nanosecond
|
||||
inline constexpr auto UNIX_TIME_NANO = "{UNIX_NANO}";
|
||||
// Formatted ISO year-month-day in a single variable
|
||||
inline constexpr auto ISO_YEAR = "{ISO_YEAR}";
|
||||
// Formatted hour:minute:second in a single variable
|
||||
|
@ -86,6 +89,7 @@ namespace blt::logging
|
|||
MS,
|
||||
NS,
|
||||
UNIX,
|
||||
UNIX_NANO,
|
||||
ISO_YEAR,
|
||||
TIME,
|
||||
FULL_TIME,
|
||||
|
@ -130,83 +134,87 @@ namespace blt::logging
|
|||
|
||||
logging_config_t& add_log_output(fs::writer_t* writer)
|
||||
{
|
||||
log_outputs.push_back(writer);
|
||||
m_log_outputs.push_back(writer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_log_format(std::string format)
|
||||
{
|
||||
log_format = std::move(format);
|
||||
m_log_format = std::move(format);
|
||||
compile();
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_error_color(std::string color)
|
||||
{
|
||||
error_color = std::move(color);
|
||||
m_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);
|
||||
m_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);
|
||||
m_log_level_names = std::move(names);
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_level(const log_level_t level)
|
||||
{
|
||||
this->level = level;
|
||||
this->m_level = level;
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_use_color(const bool use_color)
|
||||
{
|
||||
this->use_color = use_color;
|
||||
this->m_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;
|
||||
this->m_print_full_name = print_full_name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
logging_config_t& set_ensure_alignment(const bool ensure_alignment)
|
||||
{
|
||||
this->ensure_alignment = ensure_alignment;
|
||||
this->m_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};
|
||||
return {m_log_tag_tokens, m_log_tag_content};
|
||||
}
|
||||
|
||||
std::optional<std::string> generate(const std::string& user_str, const std::string& thread_name, log_level_t level, const char* file,
|
||||
i32 line) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> log_tag_content;
|
||||
std::vector<tags::detail::log_tag_token_t> log_tag_tokens;
|
||||
std::vector<std::string> m_log_tag_content;
|
||||
std::vector<tags::detail::log_tag_token_t> m_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();
|
||||
std::string error_color = get_default_error_color();
|
||||
std::array<std::string, LOG_LEVEL_COUNT> log_level_colors = get_default_log_level_colors();
|
||||
std::array<std::string, LOG_LEVEL_COUNT> log_level_names = get_default_log_level_names();
|
||||
log_level_t level = log_level_t::TRACE;
|
||||
bool use_color = true;
|
||||
std::vector<fs::writer_t*> m_log_outputs = get_default_log_outputs();
|
||||
std::string m_log_format = get_default_log_format();
|
||||
std::string m_error_color = get_default_error_color();
|
||||
std::array<std::string, LOG_LEVEL_COUNT> m_log_level_colors = get_default_log_level_colors();
|
||||
std::array<std::string, LOG_LEVEL_COUNT> m_log_level_names = get_default_log_level_names();
|
||||
log_level_t m_level = log_level_t::TRACE;
|
||||
|
||||
bool m_use_color = true;
|
||||
// if true prints the whole path to the file (eg /home/user/.../.../project/src/source.cpp:line#)
|
||||
bool print_full_name = false;
|
||||
bool m_print_full_name = false;
|
||||
// this will attempt to use the maximum possible size for each printed element, then align to that.
|
||||
// This creates output where the user message always starts at the same column.
|
||||
bool ensure_alignment = true;
|
||||
bool m_ensure_alignment = true;
|
||||
|
||||
static std::string get_default_log_format();
|
||||
static std::vector<fs::writer_t*> get_default_log_outputs();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5
|
||||
Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3
|
|
@ -30,8 +30,6 @@ 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;
|
||||
|
@ -39,6 +37,7 @@ namespace blt::logging
|
|||
struct logging_thread_context_t
|
||||
{
|
||||
std::stringstream stream;
|
||||
std::string thread_name;
|
||||
logger_t logger{stream};
|
||||
};
|
||||
|
||||
|
@ -233,7 +232,11 @@ namespace blt::logging
|
|||
|
||||
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;
|
||||
get_thread_context().thread_name = name;
|
||||
}
|
||||
|
||||
const std::string& get_thread_name()
|
||||
{
|
||||
return get_thread_context().thread_name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <blt/fs/stream_wrappers.h>
|
||||
#include <blt/logging/ansi.h>
|
||||
#include <blt/logging/logging_config.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <blt/std/system.h>
|
||||
#include <blt/std/time.h>
|
||||
|
||||
namespace blt::logging
|
||||
{
|
||||
|
@ -37,6 +40,7 @@ namespace blt::logging
|
|||
map[MILLISECOND] = log_tag_token_t::MS;
|
||||
map[NANOSECOND] = log_tag_token_t::NS;
|
||||
map[UNIX_TIME] = log_tag_token_t::UNIX;
|
||||
map[UNIX_TIME_NANO] = log_tag_token_t::UNIX_NANO;
|
||||
map[ISO_YEAR] = log_tag_token_t::ISO_YEAR;
|
||||
map[TIME] = log_tag_token_t::TIME;
|
||||
map[FULL_TIME] = log_tag_token_t::FULL_TIME;
|
||||
|
@ -51,89 +55,243 @@ namespace blt::logging
|
|||
map[STR] = log_tag_token_t::STR;
|
||||
return 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();
|
||||
m_log_tag_content.clear();
|
||||
m_log_tag_tokens.clear();
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < log_format.size(); ++i)
|
||||
for (; i < m_log_format.size(); ++i)
|
||||
{
|
||||
size_t start = i;
|
||||
while (i < log_format.size() && log_format[i] != '{')
|
||||
while (i < m_log_format.size() && m_log_format[i] != '{')
|
||||
++i;
|
||||
if (i == log_format.size() || (i < log_format.size() && (i - start) > 0))
|
||||
if (i == m_log_format.size() || (i < m_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())
|
||||
m_log_tag_content.emplace_back(std::string_view(m_log_format.data() + start, i - start));
|
||||
m_log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT);
|
||||
if (i == m_log_format.size())
|
||||
break;
|
||||
}
|
||||
start = i;
|
||||
while (i < log_format.size() && log_format[i] != '}')
|
||||
while (i < m_log_format.size() && m_log_format[i] != '}')
|
||||
++i;
|
||||
const auto tag = std::string_view(log_format.data() + start, i - start + 1);
|
||||
const auto tag = std::string_view(m_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);
|
||||
m_log_tag_tokens.emplace_back(it->second);
|
||||
}
|
||||
|
||||
if (i < log_format.size())
|
||||
if (i < m_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);
|
||||
m_log_tag_content.emplace_back(std::string_view(m_log_format.data() + i, m_log_format.size() - i));
|
||||
m_log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
std::string add_year(const tm* current_time)
|
||||
{
|
||||
return std::to_string(current_time->tm_year + 1900);
|
||||
}
|
||||
|
||||
std::string add_month(const tm* current_time, const bool ensure_alignment)
|
||||
{
|
||||
auto str = std::to_string(current_time->tm_mon + 1);
|
||||
if (ensure_alignment && str.size() < 2)
|
||||
str.insert(str.begin(), '0');
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string add_day(const tm* current_time, const bool ensure_alignment)
|
||||
{
|
||||
auto str = std::to_string(current_time->tm_mday);
|
||||
if (ensure_alignment && str.size() < 2)
|
||||
str.insert(str.begin(), '0');
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string add_hour(const tm* current_time, const bool ensure_alignment)
|
||||
{
|
||||
auto str = std::to_string(current_time->tm_hour);
|
||||
if (ensure_alignment && str.size() < 2)
|
||||
str.insert(str.begin(), '0');
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string add_minute(const tm* current_time, const bool ensure_alignment)
|
||||
{
|
||||
auto str = std::to_string(current_time->tm_min);
|
||||
if (ensure_alignment && str.size() < 2)
|
||||
str.insert(str.begin(), '0');
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string add_second(const tm* current_time, const bool ensure_alignment)
|
||||
{
|
||||
auto str = std::to_string(current_time->tm_sec);
|
||||
if (ensure_alignment && str.size() < 2)
|
||||
str.insert(str.begin(), '0');
|
||||
return str;
|
||||
}
|
||||
|
||||
std::optional<std::string> logging_config_t::generate(const std::string& user_str, const std::string& thread_name, const log_level_t level,
|
||||
const char* file, const i32 line) const
|
||||
{
|
||||
if (level < m_level)
|
||||
return {};
|
||||
|
||||
std::string fmt;
|
||||
|
||||
const std::time_t time = std::time(nullptr);
|
||||
const auto current_time = std::localtime(&time);
|
||||
const auto millis_time = system::getCurrentTimeMilliseconds();
|
||||
const auto nano_time = system::getCurrentTimeNanoseconds();
|
||||
|
||||
size_t content = 0;
|
||||
for (const auto& log_tag_token : m_log_tag_tokens)
|
||||
{
|
||||
switch (log_tag_token)
|
||||
{
|
||||
case tags::detail::log_tag_token_t::YEAR:
|
||||
fmt += add_year(current_time);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::MONTH:
|
||||
fmt += add_month(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::DAY:
|
||||
fmt += add_day(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::HOUR:
|
||||
fmt += add_hour(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::MINUTE:
|
||||
fmt += add_minute(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::SECOND:
|
||||
fmt += add_second(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::MS:
|
||||
{
|
||||
auto str = std::to_string(millis_time % 1000);
|
||||
if (m_ensure_alignment)
|
||||
{
|
||||
for (size_t i = str.size(); i < 4; ++i)
|
||||
str.insert(str.begin(), '0');
|
||||
}
|
||||
fmt += str;
|
||||
break;
|
||||
}
|
||||
case tags::detail::log_tag_token_t::NS:
|
||||
{
|
||||
auto str = std::to_string(nano_time % 1000);
|
||||
if (m_ensure_alignment)
|
||||
{
|
||||
for (size_t i = str.size(); i < 4; ++i)
|
||||
str.insert(str.begin(), '0');
|
||||
}
|
||||
fmt += str;
|
||||
break;
|
||||
}
|
||||
case tags::detail::log_tag_token_t::UNIX:
|
||||
{
|
||||
auto str = std::to_string(millis_time % 1000);
|
||||
if (m_ensure_alignment)
|
||||
{
|
||||
for (size_t i = str.size(); i < 4; ++i)
|
||||
str.insert(str.begin(), '0');
|
||||
}
|
||||
fmt += str;
|
||||
break;
|
||||
}
|
||||
case tags::detail::log_tag_token_t::UNIX_NANO:
|
||||
{
|
||||
auto str = std::to_string(nano_time);
|
||||
if (m_ensure_alignment)
|
||||
{
|
||||
for (size_t i = str.size(); i < 4; ++i)
|
||||
str.insert(str.begin(), '0');
|
||||
}
|
||||
fmt += str;
|
||||
break;
|
||||
}
|
||||
case tags::detail::log_tag_token_t::ISO_YEAR:
|
||||
{
|
||||
fmt += add_year(current_time);
|
||||
fmt += '-';
|
||||
fmt += add_month(current_time, m_ensure_alignment);
|
||||
fmt += '-';
|
||||
fmt += add_day(current_time, m_ensure_alignment);
|
||||
break;
|
||||
}
|
||||
case tags::detail::log_tag_token_t::TIME:
|
||||
fmt += add_hour(current_time, m_ensure_alignment);
|
||||
fmt += ':';
|
||||
fmt += add_minute(current_time, m_ensure_alignment);
|
||||
fmt += ':';
|
||||
fmt += add_second(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::FULL_TIME:
|
||||
fmt += add_year(current_time);
|
||||
fmt += '-';
|
||||
fmt += add_month(current_time, m_ensure_alignment);
|
||||
fmt += '-';
|
||||
fmt += add_day(current_time, m_ensure_alignment);
|
||||
fmt += ' ';
|
||||
fmt += add_hour(current_time, m_ensure_alignment);
|
||||
fmt += ':';
|
||||
fmt += add_minute(current_time, m_ensure_alignment);
|
||||
fmt += ':';
|
||||
fmt += add_second(current_time, m_ensure_alignment);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::LC:
|
||||
if (!m_use_color)
|
||||
break;
|
||||
fmt += m_log_level_colors[static_cast<u8>(level)];
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::EC:
|
||||
if (!m_use_color)
|
||||
break;
|
||||
fmt += m_error_color;
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::CEC:
|
||||
if (!m_use_color)
|
||||
break;
|
||||
if (static_cast<u8>(level) >= static_cast<u8>(log_level_t::ERROR))
|
||||
fmt += m_error_color;
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::RESET:
|
||||
if (!m_use_color)
|
||||
break;
|
||||
fmt += build(ansi::color::color_mode::RESET_ALL);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::LL:
|
||||
fmt += m_log_level_names[static_cast<u8>(level)];
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::TN:
|
||||
fmt += thread_name;
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::FILE:
|
||||
fmt += file;
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::LINE:
|
||||
fmt += std::to_string(line);
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::STR:
|
||||
fmt += user_str;
|
||||
break;
|
||||
case tags::detail::log_tag_token_t::CONTENT:
|
||||
fmt += m_log_tag_content[content++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
std::string logging_config_t::get_default_log_format()
|
||||
{
|
||||
return build(fg(ansi::color::color8_bright::CYAN)) + "[" + tags::FULL_TIME + "]" + tags::RESET + " " + tags::LOG_COLOR + "[" + tags::LOG_LEVEL
|
||||
|
|
Loading…
Reference in New Issue