Files
Z3D/include/util/logger.hpp
2024-12-22 16:58:40 +01:00

1743 lines
57 KiB
C++
Executable File

#pragma once
#include <algorithm>
#include <array>
#include <atomic>
#include <chrono>
#include <iostream>
#include <source_location>
#include <string_view>
#include <thread>
#include <tuple>
namespace ztu {
namespace logger::settings {
/**
* @brief Placeholder symbol used in format strings to signal value position.
*/
constexpr char format_symbol = '%';
/**
* @brief symbol for escaping the format symbol.
*/
constexpr char format_escape_symbol = '\\';
/**
* @brief Fall back to dynamic global config (instead of the static one) if none is provided.
*/
constexpr auto use_dynamic_global_config = false;
/**
* @brief Throw a compile time error if there are errors in a given format string..
*/
constexpr auto compile_time_exceptions = true;
/**
* @brief Throw a run time error if there are errors in a given format string..
*/
inline auto run_time_exceptions = false;
} // namespace logger::settings
namespace logger_internal {
template<typename T>
concept printeable = requires(std::ostream& os, const T& value)
{
{ os << value } -> std::same_as<std::ostream&>;
};
namespace format_errors {
using type = std::uint8_t;
static constexpr type none{ 0b0 }, too_many_values = error_t{ 0b1 }, not_enough_values{ 0b10 };
} // namespace format_errors
template<class CharT, typename... Args>
struct basic_format_string {
using string_view = std::basic_string_view<CharT>;
using size_type = string_view::size_type;
string_view view;
std::array<size_type, sizeof...(Args)> seg_lens;
format_errors::type errors{ format_errors::none };
template<size_t N>
consteval basic_format_string(const CharT (&s)[N]) : view(s) {
compile(logger::settings::compile_time_exceptions);
}
template<class S>
requires(std::is_convertible_v<const S&, string_view>)
basic_format_string(const S& s) : view(s) {
compile(logger::settings::run_time_exceptions);
}
constexpr void compile(const bool throw_exceptions) {
auto begin = view.data();
const auto end = begin + view.length();
for (auto& seg_len : seg_lens) {
const auto it = find_format_symbol(begin, end);
seg_len = it - begin;
if (it == end) {
if (throw_exceptions) {
throw std::invalid_argument("More values than placeholders.");
}
errors = format_errors::too_many_values;
begin = end;
} else {
begin = it + 1;
}
}
if (find_format_symbol(begin, end) != end) {
if (throw_exceptions) {
throw std::invalid_argument("Fewer values than placeholders.");
}
errors = format_errors::not_enough_values;
}
}
static constexpr const CharT* find_format_symbol(const CharT* begin, const CharT* const end) {
auto escaped = false;
while (begin != end) {
if (*begin == logger::settings::format_escape_symbol) {
escaped = true;
} else {
if (*begin == logger::settings::format_symbol and not escaped) {
break;
}
escaped = false;
}
++begin;
}
return begin;
}
};
template<typename... Args>
using format_string = basic_format_string<char, std::type_identity_t<Args>...>;
template<typename CharT, std::size_t N>
requires(N > 0)
struct basic_string_literal {
std::array<CharT, N> m_value{};
consteval basic_string_literal(const CharT (&str)[N]) {
std::copy_n(std::begin(str), N, m_value.begin());
m_value.back() = '\0';
}
[[nodiscard]] constexpr std::basic_string_view<CharT> view() const {
return { m_value.data(), N - 1 };
}
};
template<std::size_t N>
using string_literal = basic_string_literal<char, N>;
using flags_int_t = std::uint16_t;
} // namespace logger_internal
/**
* @brief A lightweight logging library providing color-coded output and flexible configuration.
*
* @details This namespace serves as a wrapper around std::ostream, offering a
* simple yet powerful logging interface with support for ANSI color-coded log
* levels. It provides a global logging context as well as customizable logger
* contexts, allowing users to configure output streams, log levels and more.
*/
namespace logger {
/**
* @brief Enumeration representing the log levels.
*
* The log levels are ordered from least verbose to most verbose, as follows:
* - @c mute: Indicates that no log messages should be emitted.
* - @c generic: A catch-all levels for generic log messages via 'println'.
* - @c error: Used for critical errors that require immediate attention.
* - @c warn: Used for potential issues that may need attention.
* - @c info: Used for significant events and information about the process.
* - @c log: General log messages providing information about the application's operation.
* - @c debug: Detailed debug information helpful for troubleshooting.
*/
enum class level : std::uint8_t {
mute = 0,
generic = 1,
error = 2,
warn = 3,
info = 4,
log = 5,
debug = 6
};
/**
* @brief Enumeration of feature flag for the logger class.
*
* The `flag` enum is a set of feature flag used in the logger class to control the behavior of log message output.
* Each flag corresponds to a specific feature or information component that can be included in log messages,
* providing a flexible and customizable way to tailor the levels of detail included in log outputs
* based on the specific needs of the application.
*
* @c none: Disables all flag. Log messages will only include the message without any additional information.
* @c all: Enables all available flag. Log messages will include all following features:
* @c colors: Enables color-coding for log messages, providing visual cues for different log levels.
* @c locking: Enables the use of a spin lock mechanism for thread-safe log message output.
* @c identifier -----------------------------------------------------------------------------------+
* @c thread_id -----------------------------------------------------------------------+ |
* @c function_name ------------------------------------------------------------+ | |
* @c line_number ------------------------------------------------------+ | | |
* @c filename -----------------------------------------------+ | | | |
* @c level_name ----------------------------------------+ | | | | |
* @c timestamp -------------------------------+ | | | | | |
* @c time ----------------+ | | | | | | |
* @c date ----+ | | | | | | | |
* | | | | | | | | |
* example message: [2024-1-8][19:44:9.535][1704739449535][log][main.cpp:61][main][140654793804672][tester] Hello World
*/
enum class flag : logger_internal::flags_int_t {
none = 0,
all = std::numeric_limits<logger_internal::flags_int_t>::max(),
colors = (1 << 0),
locking = (1 << 1),
date = (1 << 2),
time = (1 << 3),
timestamp = (1 << 4),
level_name = (1 << 5),
filename = (1 << 6),
line_number = (1 << 7),
function_name = (1 << 8),
thread_id = (1 << 9)
};
} // namespace logger
} // namespace ztu
[[nodiscard]] constexpr ztu::logger::flag operator|(const ztu::logger::flag& a, const ztu::logger::flag& b) {
return static_cast<ztu::logger::flag>(
static_cast<ztu::logger_internal::flags_int_t>(a) | static_cast<ztu::logger_internal::flags_int_t>(b)
);
}
[[nodiscard]] constexpr ztu::logger::flag operator&(const ztu::logger::flag& a, const ztu::logger::flag& b) {
return static_cast<ztu::logger::flag>(
static_cast<ztu::logger_internal::flags_int_t>(a) & static_cast<ztu::logger_internal::flags_int_t>(b)
);
}
[[nodiscard]] constexpr ztu::logger::flag operator^(const ztu::logger::flag& a, const ztu::logger::flag& b) {
return static_cast<ztu::logger::flag>(
static_cast<ztu::logger_internal::flags_int_t>(a) ^ static_cast<ztu::logger_internal::flags_int_t>(b)
);
}
[[nodiscard]] constexpr ztu::logger::flag operator~(const ztu::logger::flag& a) {
return static_cast<ztu::logger::flag>(~static_cast<ztu::logger_internal::flags_int_t>(a));
}
constexpr ztu::logger::flag& operator|=(ztu::logger::flag& a, const ztu::logger::flag& b) {
return a = a | b;
}
constexpr ztu::logger::flag& operator&=(ztu::logger::flag& a, const ztu::logger::flag& b) {
return a = a & b;
}
constexpr ztu::logger::flag& operator^=(ztu::logger::flag& a, const ztu::logger::flag& b) {
return a = a ^ b;
}
inline std::ostream& operator<<(std::ostream& out, ztu::logger::level level) {
switch (level) {
using enum ztu::logger::level;
case mute:
return out << "mute";
case error:
return out << "error";
case warn:
return out << "warn";
case info:
return out << "info";
case log:
return out << "log";
case debug:
return out << "debug";
case generic:
return out << "generic";
default:
return out << "unknown(" << std::to_string(static_cast<int>(level)) << ")";
}
}
namespace ztu {
namespace logger {
/**
* @brief Context structure for configuring the behavior of the logger class.
*
* The `context` struct provides a means to configure the logger's behavior by
* specifying the output streams, log message formatting flag, log levels, and
* an optional spin lock for thread safety.
*
* @c out: Pointer to the output stream for standard log messages.
* @c err: Pointer to the output stream for error log messages.
* @c lock: Atomic flag used for thread-safe log message output when the `locking` flag is enabled.
*/
struct context {
std::ostream* out;
std::ostream* err;
std::atomic_flag lock = ATOMIC_FLAG_INIT;
inline context(std::ostream&, std::ostream&);
};
/**
* @brief Dynamic config structure for configuring the behavior of the logger class.
*
* The `context` struct provides a means to configure the logger's behavior by sspecifying the output streams,
* log message formatting flag, log levels, and an optional spin lock for thread safety.
*
* @param flag Flags representing the formatting options for log messages. See the flag enum for details.
* @param threshold Log levels setting, controlling the verbosity of logged messages. See the levels enum for details.
* @param identifier Atomic flag used for thread-safe log message output when the `locking` flag is enabled.
*/
struct dynamic_config {
flag flags;
level threshold;
std::string identifier{};
};
/**
* @brief Static config structure for configuring the behavior of the logger class.
*
* The `context` struct provides a means to configure the logger's behavior by sspecifying the output streams,
* log message formatting flag, log levels, and an optional spin lock for thread safety.
*
* @tparam Flags Flags representing the formatting options for log messages. See the flag enum for details.
* @tparam Threshold Log levels setting, controlling the verbosity of logged messages. See the levels enum for details.
* @tparam Identifier Atomic flag used for thread-safe log message output when the `locking` flag is enabled.
*/
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
struct static_config {
static constexpr auto flags = Flags;
static constexpr auto threshold = Threshold;
static constexpr auto identifier = Identifier.view();
};
/**
* @brief Returns the global fallback context used in all logging functions.
*
* @return A reference to the global context.
*/
inline context& global_context();
/**
* @brief Returns the global dynamic fallback config used in all logging functions.
*
* @return A reference to the global dynamic config.
*/
inline dynamic_config& global_dynamic_config();
/**
* @brief The global static fallback config used in all logging functions.
*/
inline constexpr auto global_static_config = static_config<
(flag::colors | flag::locking /*| flag::time*/ | flag::level_name | flag::filename | flag::line_number),
level::debug,
"">{};
namespace functions {
/**
* @brief Formats and logs an error message using the @c global_handle.
*
* The format string may contain placeholders (@c fmt_symbol)
* replaced by corresponding values provided in the arguments (@c args).
*
* @tparam Args Variadic template for the types of arguments passed to the format string.
* @param ctx The logging context used for writing out the formatted message.
* @param cfg The config for the message formatting and filtering.
* @param fmt The format string for the error message, supporting placeholders.
* @param args The values to be formatted and included in the error message.
*/
template<logger_internal::printeable... Args>
struct error {
explicit error(
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit error(
context& ctx,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit error(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit error(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit error(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit error(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
};
template<logger_internal::printeable... Args>
error(logger_internal::format_string<Args...>, Args&&...) -> error<Args...>;
template<logger_internal::printeable... Args>
error(context& ctx, logger_internal::format_string<Args...>, Args&&...) -> error<Args...>;
template<logger_internal::printeable... Args>
error(const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> error<Args...>;
template<logger_internal::printeable... Args>
error(context& ctx, const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> error<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
error(const static_config<Flags, Threshold, Identifier>& cfg, logger_internal::format_string<Args...>, Args&&...)
-> error<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
error(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...>,
Args&&...
) -> error<Args...>;
/**
* @brief Formats and logs a warn message using the @c global_handle.
*
* The format string may contain placeholders (@c fmt_symbol)
* replaced by corresponding values provided in the arguments (@c args).
*
* @tparam Args Variadic template for the types of arguments passed to the format string.
* @param ctx The logging context used for writing out the formatted message.
* @param cfg The config for the message formatting and filtering.
* @param fmt The format string for the warn message, supporting placeholders.
* @param args The values to be formatted and included in the warn message.
*/
template<logger_internal::printeable... Args>
struct warn {
explicit warn(
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit warn(
context& ctx,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit warn(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit warn(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit warn(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit warn(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
};
template<logger_internal::printeable... Args>
warn(logger_internal::format_string<Args...>, Args&&...) -> warn<Args...>;
template<logger_internal::printeable... Args>
warn(context& ctx, logger_internal::format_string<Args...>, Args&&...) -> warn<Args...>;
template<logger_internal::printeable... Args>
warn(const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> warn<Args...>;
template<logger_internal::printeable... Args>
warn(context& ctx, const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> warn<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
warn(const static_config<Flags, Threshold, Identifier>& cfg, logger_internal::format_string<Args...>, Args&&...)
-> warn<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
warn(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...>,
Args&&...
) -> warn<Args...>;
/**
* @brief Formats and logs an info message using the @c global_handle.
*
* The format string may contain placeholders (@c fmt_symbol)
* replaced by corresponding values provided in the arguments (@c args).
*
* @tparam Args Variadic template for the types of arguments passed to the format string.
* @param ctx The logging context used for writing out the formatted message.
* @param cfg The config for the message formatting and filtering.
* @param fmt The format string for the info message, supporting placeholders.
* @param args The values to be formatted and included in the info message.
*/
template<logger_internal::printeable... Args>
struct info {
explicit info(
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit info(
context& ctx,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit info(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit info(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit info(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit info(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
};
template<logger_internal::printeable... Args>
info(logger_internal::format_string<Args...>, Args&&...) -> info<Args...>;
template<logger_internal::printeable... Args>
info(context& ctx, logger_internal::format_string<Args...>, Args&&...) -> info<Args...>;
template<logger_internal::printeable... Args>
info(const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> info<Args...>;
template<logger_internal::printeable... Args>
info(context& ctx, const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> info<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
info(const static_config<Flags, Threshold, Identifier>& cfg, logger_internal::format_string<Args...>, Args&&...)
-> info<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
info(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...>,
Args&&...
) -> info<Args...>;
/**
* @brief Formats and logs a log message using the @c global_handle.
*
* The format string may contain placeholders (@c fmt_symbol)
* replaced by corresponding values provided in the arguments (@c args).
*
* @tparam Args Variadic template for the types of arguments passed to the format string.
* @param ctx The logging context used for writing out the formatted message.
* @param cfg The config for the message formatting and filtering.
* @param fmt The format string for the log message, supporting placeholders.
* @param args The values to be formatted and included in the log message.
*/
template<logger_internal::printeable... Args>
struct log {
explicit log(
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit log(
context& ctx,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit log(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit log(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit log(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit log(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
};
template<logger_internal::printeable... Args>
log(logger_internal::format_string<Args...>, Args&&...) -> log<Args...>;
template<logger_internal::printeable... Args>
log(context& ctx, logger_internal::format_string<Args...>, Args&&...) -> log<Args...>;
template<logger_internal::printeable... Args>
log(const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> log<Args...>;
template<logger_internal::printeable... Args>
log(context& ctx, const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> log<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
log(const static_config<Flags, Threshold, Identifier>& cfg, logger_internal::format_string<Args...>, Args&&...)
-> log<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
log(context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...>,
Args&&...) -> log<Args...>;
/**
* @brief Formats and logs a debug message using the @c global_handle.
*
* The format string may contain placeholders (@c fmt_symbol)
* replaced by corresponding values provided in the arguments (@c args).
*
* @tparam Args Variadic template for the types of arguments passed to the format string.
* @param ctx The logging context used for writing out the formatted message.
* @param cfg The config for the message formatting and filtering.
* @param fmt The format string for the debug message, supporting placeholders.
* @param args The values to be formatted and included in the debug message.
*/
template<logger_internal::printeable... Args>
struct debug {
explicit debug(
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit debug(
context& ctx,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit debug(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit debug(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit debug(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit debug(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
};
template<logger_internal::printeable... Args>
debug(logger_internal::format_string<Args...>, Args&&...) -> debug<Args...>;
template<logger_internal::printeable... Args>
debug(context& ctx, logger_internal::format_string<Args...>, Args&&...) -> debug<Args...>;
template<logger_internal::printeable... Args>
debug(const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> debug<Args...>;
template<logger_internal::printeable... Args>
debug(context& ctx, const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> debug<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
debug(const static_config<Flags, Threshold, Identifier>& cfg, logger_internal::format_string<Args...>, Args&&...)
-> debug<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
debug(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...>,
Args&&...
) -> debug<Args...>;
/**
* @brief Formats and logs a generic message using the @c global_handle.
*
* The format string may contain placeholders (@c fmt_symbol)
* replaced by corresponding values provided in the arguments (@c args).
*
* @tparam Args Variadic template for the types of arguments passed to the format string.
* @param ctx The logging context used for writing out the formatted message.
* @param cfg The config for the message formatting and filtering.
* @param fmt The format string for the generic message, supporting placeholders.
* @param args The values to be formatted and included in the generic message.
*/
template<logger_internal::printeable... Args>
struct println {
explicit println(
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit println(
context& ctx,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit println(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit println(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
explicit println(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
explicit println(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location = std::source_location::current()
);
};
template<logger_internal::printeable... Args>
println(logger_internal::format_string<Args...>, Args&&...) -> println<Args...>;
template<logger_internal::printeable... Args>
println(context& ctx, logger_internal::format_string<Args...>, Args&&...) -> println<Args...>;
template<logger_internal::printeable... Args>
println(const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...) -> println<Args...>;
template<logger_internal::printeable... Args>
println(context& ctx, const dynamic_config& cfg, logger_internal::format_string<Args...>, Args&&...)
-> println<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
println(const static_config<Flags, Threshold, Identifier>& cfg, logger_internal::format_string<Args...>, Args&&...)
-> println<Args...>;
template<flag Flags, level Threshold, logger_internal::string_literal Identifier, logger_internal::printeable... Args>
println(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...>,
Args&&...
) -> println<Args...>;
} // namespace functions
} // namespace logger
namespace logger_internal {
enum class color : std::uint8_t {
reset = 0,
black = 30,
red = 31,
green = 32,
yellow = 33,
blue = 34,
magenta = 35,
cyan = 36,
white = 37
};
constexpr std::size_t num_digits(std::uint32_t n, const std::uint32_t base = 10) {
if (n < base) {
return 1;
}
auto digits = std::size_t{};
while (n > 0) {
n /= base;
++digits;
}
return digits;
}
template<std::uint32_t N, std::uint32_t B = 10>
constexpr auto int_to_str() {
auto str = std::array<char, num_digits(N, B)>{};
auto index = str.size() - 1;
auto num = N;
do {
str[index] = static_cast<char>('0' + num % B);
num /= B;
} while (index--);
return str;
}
template<color color, bool bright>
constexpr auto create_ansi_color() {
constexpr auto color_index = static_cast<std::uint8_t>(color);
constexpr auto color_index_str = int_to_str<color_index>();
constexpr auto prefix = std::string_view("\x1B[");
constexpr auto postfix = [&]() -> std::string_view {
if constexpr (bright) {
return ";1m";
} else {
return "m";
}
}();
constexpr auto color_str_length = (prefix.size() + color_index_str.size() + postfix.size());
std::array<char, color_str_length> color_str{};
auto it = color_str.begin();
const auto append = [&it](auto begin, const auto end) {
while (begin != end) {
*it++ = *begin++;
}
};
append(prefix.begin(), prefix.end());
append(color_index_str.begin(), color_index_str.end());
append(postfix.begin(), postfix.end());
return color_str;
}
inline constexpr auto reset_color_array = create_ansi_color<color::reset, false>();
inline constexpr auto reset_color = std::string_view(reset_color_array.data(), reset_color_array.size());
inline constexpr auto internal_color_array = create_ansi_color<color::black, true>();
inline constexpr auto internal_color = std::string_view(internal_color_array.data(), internal_color_array.size());
inline constexpr std::size_t level_count = 6;
inline constexpr std::array<std::string_view, level_count> level_names{ "generic", "error", "warning",
"info", "log", "debug" };
template<bool bright, color... colors>
constexpr auto create_color_tuple() {
return std::make_tuple(create_ansi_color<colors, bright>()...);
}
template<typename... Ts, std::size_t... Is>
constexpr auto build_string_lookup(const std::tuple<Ts...>& string_tuple, std::index_sequence<Is...>) {
return std::array{ std::string_view(std::get<Is>(string_tuple).data(), std::get<Is>(string_tuple).size())... };
}
inline constexpr auto level_dark_color_tuple = create_color_tuple<
false,
color::white,
color::red,
color::yellow,
color::green,
color::blue,
color::magenta>();
inline constexpr auto level_dark_color_lookup = build_string_lookup(
level_dark_color_tuple, std::make_index_sequence<level_count>{}
);
inline constexpr auto level_bright_color_tuple = create_color_tuple<
true,
color::white,
color::red,
color::yellow,
color::green,
color::blue,
color::magenta>();
inline constexpr auto level_bright_color_lookup = build_string_lookup(
level_bright_color_tuple, std::make_index_sequence<level_count>{}
);
inline void print_escaped_string(
std::ostream& out,
const std::string_view& reset_clr,
const std::string_view& internal_clr,
const char* begin,
const char* const end
) {
auto escaped = false;
auto it = begin;
while (it != end) {
if (*it == logger::settings::format_escape_symbol) {
escaped = true;
} else {
if (*it == logger::settings::format_symbol) {
out.write(begin, it - begin - escaped);
begin = it + 1 - escaped;
if (not escaped) {
out << internal_clr << logger::settings::format_symbol << reset_clr;
}
}
escaped = false;
}
++it;
}
out.write(begin, it - begin);
}
template<typename Fmt>
void print_format_impl(
std::ostream& out,
const std::string_view&,
std::string_view& reset_clr,
const std::string_view& internal_clr,
std::size_t pos,
bool&,
const Fmt& fmt
) {
print_escaped_string(out, reset_clr, internal_clr, &fmt.view[pos], fmt.view.data() + fmt.view.length());
}
template<typename Fmt, printeable Arg, printeable... Rest>
void print_format_impl(
std::ostream& out,
const std::string_view& value_clr,
std::string_view& reset_clr,
const std::string_view& internal_clr,
std::size_t pos,
bool& excess_value,
Fmt& fmt,
Arg&& arg,
Rest&&... rest
) {
const auto arg_index = fmt.seg_lens.size() - sizeof...(Rest) - 1;
const auto len = fmt.seg_lens[arg_index];
const auto str = &fmt.view[pos];
print_escaped_string(out, reset_clr, internal_clr, str, str + len);
pos += len;
if (pos == fmt.view.length()) {
if (excess_value) {
out << ',';
} else {
out << internal_clr << " <[";
excess_value = true;
}
reset_clr = internal_clr;
} else {
++pos;
}
out << value_clr << arg << reset_clr;
print_format_impl(out, value_clr, reset_clr, internal_clr, pos, excess_value, fmt, std::forward<Rest>(rest)...);
}
template<typename Fmt, printeable... Args>
void print_format(
std::ostream& out,
const std::string_view& value_clr,
std::string_view& reset_clr,
const std::string_view& internal_clr,
Fmt& fmt,
Args&&... args
) {
const auto reset = reset_clr;
auto excess_value = false;
print_format_impl(out, value_clr, reset_clr, internal_clr, 0ul, excess_value, fmt, std::forward<Args>(args)...);
if (fmt.errors & format_errors::too_many_values) {
out << "] Excess value(s)>";
} else if (fmt.errors & format_errors::not_enough_values) {
out << internal_clr << " <Excess placeholder(s)>";
}
out << reset;
}
template<printeable... Args>
void println_impl(
logger::context& ctx,
const logger::dynamic_config& cfg,
const std::source_location& location,
logger::level threshold,
format_string<Args...> fmt,
Args&&... args
) {
using namespace logger;
const auto current_level_index = static_cast<std::uint8_t>(cfg.threshold);
auto level_index = static_cast<std::uint8_t>(threshold);
if (current_level_index < level_index) {
return;
}
if ((cfg.flags & flag::locking) != flag::none) {
while (ctx.lock.test_and_set(std::memory_order_relaxed)) {
}
}
level_index = std::min(level_index, static_cast<std::uint8_t>(level_count)) - 1;
std::string_view bright_clr, dark_clr, reset_clr, internal_clr;
if ((cfg.flags & flag::colors) != flag::none) {
bright_clr = level_bright_color_lookup[level_index];
dark_clr = level_dark_color_lookup[level_index];
reset_clr = reset_color;
internal_clr = internal_color;
}
auto& stream = (threshold == level::warn or threshold == level::error) ? *ctx.err : *ctx.out;
const auto print_prefix = [&](const auto&... values) {
stream << '[' << bright_clr;
((stream << values), ...) << reset_clr << ']';
};
static constexpr auto needs_clock = flag::date | flag::time | flag::timestamp;
if ((cfg.flags & needs_clock) != flag::none) {
namespace chr = std::chrono;
using clock = chr::system_clock;
const auto now = clock::now();
static constexpr auto needs_time = flag::date | flag::time;
if ((cfg.flags & needs_time) != flag::none) {
const auto time = clock::to_time_t(now);
const auto local_time = std::localtime(&time);
if ((cfg.flags & flag::date) != flag::none) {
print_prefix(1'900 + local_time->tm_year, '-', 1 + local_time->tm_mon, '-', local_time->tm_mday);
}
if ((cfg.flags & flag::time) != flag::none) {
const auto truncated = std::chrono::system_clock::from_time_t(time);
const auto millis = chr::duration_cast<chr::milliseconds>(now - truncated).count();
print_prefix(local_time->tm_hour, ':', local_time->tm_min, ':', local_time->tm_sec, '.', millis);
}
}
if ((cfg.flags & flag::timestamp) != flag::none) {
const auto timestamp = chr::duration_cast<chr::milliseconds>(now.time_since_epoch());
print_prefix(timestamp.count());
}
}
if ((cfg.flags & flag::level_name) != flag::none) {
print_prefix(level_names[level_index]);
}
if ((cfg.flags & flag::filename) != flag::none) {
if ((cfg.flags & flag::line_number) != flag::none) {
print_prefix(' ', location.file_name(), ':', std::dec, location.line());
} else {
print_prefix(location.file_name());
}
} else if ((cfg.flags & flag::line_number) != flag::none) {
print_prefix(std::dec, location.line());
}
if ((cfg.flags & flag::function_name) != flag::none) {
print_prefix(location.function_name());
}
if ((cfg.flags & flag::thread_id) != flag::none) {
print_prefix(std::this_thread::get_id());
}
if (not cfg.identifier.empty()) {
print_prefix(cfg.identifier);
}
static constexpr auto prefix_flags = ~(flag::colors | flag::locking);
if ((cfg.flags & prefix_flags) != flag::none or not cfg.identifier.empty()) {
stream << ' ';
}
logger_internal::print_format(stream, dark_clr, reset_clr, internal_clr, fmt, std::forward<Args>(args)...);
stream << '\n';
ctx.lock.clear();
}
template<logger::flag Flags, logger::level Threshold, string_literal Identifier, printeable... Args>
void println_impl(
logger::context& ctx,
const logger::static_config<Flags, Threshold, Identifier>&,
const std::source_location& location,
logger::level threshold,
format_string<Args...> fmt,
Args&&... args
) {
using namespace logger;
constexpr auto current_level_index = static_cast<std::uint8_t>(Threshold);
auto level_index = static_cast<std::uint8_t>(threshold);
if (current_level_index < level_index) {
return;
}
if constexpr ((Flags & flag::locking) != flag::none) {
while (ctx.lock.test_and_set(std::memory_order_relaxed)) {
}
}
level_index = std::min(level_index, static_cast<std::uint8_t>(level_count)) - 1;
std::string_view bright_clr, dark_clr, reset_clr, internal_clr;
if constexpr ((Flags & flag::colors) != flag::none) {
bright_clr = level_bright_color_lookup[level_index];
dark_clr = level_dark_color_lookup[level_index];
reset_clr = reset_color;
internal_clr = internal_color;
}
auto& stream = (threshold == level::warn or threshold == level::error) ? *ctx.err : *ctx.out;
const auto print_prefix = [&](const auto&... values) {
stream << '[' << bright_clr;
((stream << values), ...) << reset_clr << ']';
};
static constexpr auto needs_clock = flag::date | flag::time | flag::timestamp;
if constexpr ((Flags & needs_clock) != flag::none) {
namespace chr = std::chrono;
using clock = chr::system_clock;
const auto now = clock::now();
static constexpr auto needs_time = flag::date | flag::time;
if constexpr ((Flags & needs_time) != flag::none) {
const auto time = clock::to_time_t(now);
const auto local_time = std::localtime(&time);
if constexpr ((Flags & flag::date) != flag::none) {
print_prefix(1'900 + local_time->tm_year, '-', 1 + local_time->tm_mon, '-', local_time->tm_mday);
}
if constexpr ((Flags & flag::time) != flag::none) {
const auto truncated = std::chrono::system_clock::from_time_t(time);
const auto millis = chr::duration_cast<chr::milliseconds>(now - truncated).count();
print_prefix(local_time->tm_hour, ':', local_time->tm_min, ':', local_time->tm_sec, '.', millis);
}
}
if ((Flags & flag::timestamp) != flag::none) {
const auto timestamp = chr::duration_cast<chr::milliseconds>(now.time_since_epoch());
print_prefix(timestamp.count());
}
}
if constexpr ((Flags & flag::level_name) != flag::none) {
print_prefix(level_names[level_index]);
}
if constexpr ((Flags & flag::filename) != flag::none) {
if constexpr ((Flags & flag::line_number) != flag::none) {
print_prefix(' ', location.file_name(), ':', std::dec, location.line());
} else {
print_prefix(location.file_name());
}
} else if constexpr ((Flags & flag::line_number) != flag::none) {
print_prefix(std::dec, location.line());
}
if constexpr ((Flags & flag::function_name) != flag::none) {
print_prefix(location.function_name());
}
if constexpr ((Flags & flag::thread_id) != flag::none) {
print_prefix(std::this_thread::get_id());
}
constexpr auto identifier = Identifier.view();
if constexpr (not identifier.empty()) {
print_prefix(identifier);
}
static constexpr auto prefix_flags = ~(flag::colors | flag::locking);
if constexpr ((Flags & prefix_flags) != flag::none or not identifier.empty()) {
stream << ' ';
}
logger_internal::print_format(stream, dark_clr, reset_clr, internal_clr, fmt, std::forward<Args>(args)...);
stream << '\n';
ctx.lock.clear();
}
} // namespace logger_internal
namespace logger {
context::context(std::ostream& new_out, std::ostream& new_err) : out{ &new_out }, err{ &new_err } {
}
context& global_context() {
static auto ctx = context(std::cout, std::cerr);
return ctx;
}
dynamic_config& global_dynamic_config() {
static auto cfg = dynamic_config{ (flag::colors | flag::locking | flag::time | flag::level_name | flag::filename |
flag::line_number),
level::debug,
"" };
return cfg;
}
namespace functions {
template<logger_internal::printeable... Args>
error<Args...>::error(
logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(
global_context(),
global_dynamic_config(),
location,
level::error,
fmt,
std::forward<Args>(args)...
);
} else {
println_impl(global_context(), global_static_config, location, level::error, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
error<Args...>::error(
context& ctx, logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(ctx, global_dynamic_config(), location, level::error, fmt, std::forward<Args>(args)...);
} else {
println_impl(ctx, global_static_config, location, level::error, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
error<Args...>::error(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::error, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
error<Args...>::error(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::error, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
error<Args...>::error(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::error, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
error<Args...>::error(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::error, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
warn<Args...>::warn(logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(
global_context(),
global_dynamic_config(),
location,
level::warn,
fmt,
std::forward<Args>(args)...
);
} else {
println_impl(global_context(), global_static_config, location, level::warn, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
warn<Args...>::warn(
context& ctx, logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(ctx, global_dynamic_config(), location, level::warn, fmt, std::forward<Args>(args)...);
} else {
println_impl(ctx, global_static_config, location, level::warn, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
warn<Args...>::warn(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::warn, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
warn<Args...>::warn(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::warn, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
warn<Args...>::warn(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::warn, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
warn<Args...>::warn(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::warn, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
info<Args...>::info(logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(
global_context(),
global_dynamic_config(),
location,
level::info,
fmt,
std::forward<Args>(args)...
);
} else {
println_impl(global_context(), global_static_config, location, level::info, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
info<Args...>::info(
context& ctx, logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(ctx, global_dynamic_config(), location, level::info, fmt, std::forward<Args>(args)...);
} else {
println_impl(ctx, global_static_config, location, level::info, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
info<Args...>::info(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::info, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
info<Args...>::info(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::info, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
info<Args...>::info(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::info, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
info<Args...>::info(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::info, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
log<Args...>::log(logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(global_context(), global_dynamic_config(), location, level::log, fmt, std::forward<Args>(args)...);
} else {
println_impl(global_context(), global_static_config, location, level::log, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
log<Args...>::log(
context& ctx, logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(ctx, global_dynamic_config(), location, level::log, fmt, std::forward<Args>(args)...);
} else {
println_impl(ctx, global_static_config, location, level::log, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
log<Args...>::log(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::log, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
log<Args...>::log(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::log, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
log<Args...>::log(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::log, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
log<Args...>::log(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::log, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
debug<Args...>::debug(
logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(
global_context(),
global_dynamic_config(),
location,
level::debug,
fmt,
std::forward<Args>(args)...
);
} else {
println_impl(global_context(), global_static_config, location, level::debug, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
debug<Args...>::debug(
context& ctx, logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(ctx, global_dynamic_config(), location, level::debug, fmt, std::forward<Args>(args)...);
} else {
println_impl(ctx, global_static_config, location, level::debug, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
debug<Args...>::debug(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::debug, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
debug<Args...>::debug(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::debug, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
debug<Args...>::debug(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::debug, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
debug<Args...>::debug(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::debug, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
println<Args...>::println(
logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(
global_context(),
global_dynamic_config(),
location,
level::generic,
fmt,
std::forward<Args>(args)...
);
} else {
println_impl(
global_context(),
global_static_config,
location,
level::generic,
fmt,
std::forward<Args>(args)...
);
}
}
template<logger_internal::printeable... Args>
println<Args...>::println(
context& ctx, logger_internal::format_string<Args...> fmt, Args&&... args, const std::source_location& location
) {
if constexpr (settings::use_dynamic_global_config) {
println_impl(ctx, global_dynamic_config(), location, level::generic, fmt, std::forward<Args>(args)...);
} else {
println_impl(ctx, global_static_config, location, level::generic, fmt, std::forward<Args>(args)...);
}
}
template<logger_internal::printeable... Args>
println<Args...>::println(
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::generic, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
println<Args...>::println(
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(global_context(), cfg, location, level::generic, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
println<Args...>::println(
context& ctx,
const dynamic_config& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::generic, fmt, std::forward<Args>(args)...);
}
template<logger_internal::printeable... Args>
template<flag Flags, level Threshold, logger_internal::string_literal Identifier>
println<Args...>::println(
context& ctx,
const static_config<Flags, Threshold, Identifier>& cfg,
logger_internal::format_string<Args...> fmt,
Args&&... args,
const std::source_location& location
) {
println_impl(ctx, cfg, location, level::generic, fmt, std::forward<Args>(args)...);
}
} // namespace functions
using namespace functions;
} // namespace logger
} // namespace ztu