Skip to content

Commit

Permalink
Merge pull request #683 from elbeno/custom-log-level
Browse files Browse the repository at this point in the history
✨ Allow custom log levels
  • Loading branch information
lukevalenty authored Jan 16, 2025
2 parents 7371d3b + 4dbdb14 commit 903437b
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 100 deletions.
16 changes: 9 additions & 7 deletions include/flow/impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <flow/common.hpp>
#include <flow/log.hpp>
#include <log/env.hpp>
#include <log/level.hpp>
#include <log/log.hpp>

#include <stdx/ct_string.hpp>
Expand All @@ -20,9 +22,9 @@ constexpr auto run_func() -> void {
if constexpr (not FlowName.empty()) {
using log_spec_t =
decltype(get_log_spec<CTNode, log_spec_id_t<FlowName>>());
CIB_LOG(typename log_spec_t::flavor, log_spec_t::level,
"flow.{}({})", typename CTNode::type_t{},
typename CTNode::name_t{});
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
CIB_LOG(typename log_spec_t::flavor, "flow.{}({})",
typename CTNode::type_t{}, typename CTNode::name_t{});
}
typename CTNode::func_t{}();
}
Expand Down Expand Up @@ -60,16 +62,16 @@ template <stdx::ct_string Name, auto... FuncPtrs> struct inlined_func_list {

if constexpr (loggingEnabled) {
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
CIB_LOG(typename log_spec_t::flavor, log_spec_t::level,
"flow.start({})", name);
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
CIB_LOG(typename log_spec_t::flavor, "flow.start({})", name);
}

(FuncPtrs(), ...);

if constexpr (loggingEnabled) {
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
CIB_LOG(typename log_spec_t::flavor, log_spec_t::level,
"flow.end({})", name);
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
CIB_LOG(typename log_spec_t::flavor, "flow.end({})", name);
}
}
};
Expand Down
21 changes: 11 additions & 10 deletions include/log/catalog/mipi_encoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@

namespace logging::mipi {
namespace detail {
template <logging::level L, typename S, typename... Args>
constexpr auto to_message() {
template <auto L, typename S, typename... Args> constexpr auto to_message() {
constexpr auto s = S::value;
using char_t = typename std::remove_cv_t<decltype(s)>::value_type;
return [&]<std::size_t... Is>(std::integer_sequence<std::size_t, Is...>) {
return sc::message<
L, sc::undefined<sc::args<Args...>, char_t, s[Is]...>>{};
static_cast<logging::level>(L),
sc::undefined<sc::args<Args...>, char_t, s[Is]...>>{};
}(std::make_integer_sequence<std::size_t, std::size(s)>{});
}

Expand Down Expand Up @@ -103,21 +103,22 @@ using catalog_msg_t =
template <typename TDestinations> struct log_handler {
constexpr explicit log_handler(TDestinations &&ds) : dests{std::move(ds)} {}

template <logging::level Level, typename Env, typename FilenameStringType,
template <typename Env, typename FilenameStringType,
typename LineNumberType, typename MsgType>
ALWAYS_INLINE auto log(FilenameStringType, LineNumberType,
MsgType const &msg) -> void {
log_msg<Level, Env>(msg);
log_msg<Env>(msg);
}

template <logging::level Level, typename Env, typename Msg>
template <typename Env, typename Msg>
ALWAYS_INLINE auto log_msg(Msg msg) -> void {
msg.apply([&]<typename S, typename... Args>(S, Args... args) {
using Message = decltype(detail::to_message<Level, S, Args...>());
constexpr auto L = stdx::to_underlying(get_level(Env{}).value);
using Message = decltype(detail::to_message<L, S, Args...>());
using Module =
decltype(detail::to_module<get_module(Env{}).value>());
dispatch_message<Level>(catalog<Message>(), module<Module>(),
static_cast<std::uint32_t>(args)...);
dispatch_message<L>(catalog<Message>(), module<Module>(),
static_cast<std::uint32_t>(args)...);
});
}

Expand Down Expand Up @@ -173,7 +174,7 @@ template <typename TDestinations> struct log_handler {
dests);
}

template <logging::level Level, std::same_as<std::uint32_t>... MsgDataTypes>
template <auto Level, std::same_as<std::uint32_t>... MsgDataTypes>
ALWAYS_INLINE auto dispatch_message(string_id id,
[[maybe_unused]] module_id m,
MsgDataTypes... msg_data) -> void {
Expand Down
15 changes: 13 additions & 2 deletions include/log/env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ template <std::size_t... Is> struct for_each_pair<std::index_sequence<Is...>> {
2 * Is + 1>::value.value>()>...>;
};
} // namespace detail

template <typename Env = env<>>
constexpr auto make_env = []<detail::autowrap... Args> {
using new_env_t = typename detail::for_each_pair<
std::make_index_sequence<sizeof...(Args) / 2>>::template type<Args...>;
return boost::mp11::mp_append<new_env_t, Env>{};
};

template <detail::autowrap... Args>
using make_env_t = decltype(make_env<>.template operator()<Args...>());
} // namespace logging

using cib_log_env_t = logging::env<>;
Expand All @@ -82,10 +92,11 @@ using cib_log_env_t = logging::env<>;
#endif

#define CIB_LOG_ENV_DECL(...) \
[[maybe_unused]] typedef decltype([]<logging::detail::autowrap... Args> { \
[[maybe_unused]] typedef decltype([]<logging::detail:: \
autowrap... _env_args> { \
using new_env_t = \
typename logging::detail::for_each_pair<std::make_index_sequence< \
sizeof...(Args) / 2>>::template type<Args...>; \
sizeof...(_env_args) / 2>>::template type<_env_args...>; \
return boost::mp11::mp_append<new_env_t, cib_log_env_t>{}; \
}.template operator()<__VA_ARGS__>()) cib_log_env_t

Expand Down
13 changes: 9 additions & 4 deletions include/log/fmt/logger.hpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
#pragma once

#include <log/level.hpp>
#include <log/log.hpp>
#include <log/module.hpp>

#include <stdx/ct_format.hpp>
#include <stdx/tuple.hpp>
#include <stdx/tuple_algorithms.hpp>
#include <stdx/utility.hpp>

#include <fmt/format.h>

#include <chrono>
#include <type_traits>
#include <utility>

template <auto L> struct fmt::formatter<logging::level_constant<L>> {
template <logging::level L>
struct fmt::formatter<std::integral_constant<logging::level, L>> {
constexpr static auto parse(format_parse_context &ctx) {
return ctx.begin();
}

template <typename FormatContext>
auto format(logging::level_constant<L>, FormatContext &ctx) const {
auto format(std::integral_constant<logging::level, L>,
FormatContext &ctx) const {
return ::fmt::format_to(ctx.out(), logging::to_text<L>());
}
};
Expand All @@ -27,7 +32,7 @@ namespace logging::fmt {
template <typename TDestinations> struct log_handler {
constexpr explicit log_handler(TDestinations &&ds) : dests{std::move(ds)} {}

template <logging::level L, typename Env, typename FilenameStringType,
template <typename Env, typename FilenameStringType,
typename LineNumberType, typename MsgType>
auto log(FilenameStringType, LineNumberType, MsgType const &msg) -> void {
auto const currentTime =
Expand All @@ -38,7 +43,7 @@ template <typename TDestinations> struct log_handler {
stdx::for_each(
[&](auto &out) {
::fmt::format_to(out, "{:>8}us {} [{}]: ", currentTime,
level_constant<L>{}, get_module(Env{}).value);
get_level(Env{}), get_module(Env{}).value);
msg.apply(
[&]<typename StringType>(StringType, auto const &...args) {
::fmt::format_to(out, StringType::value, args...);
Expand Down
12 changes: 11 additions & 1 deletion include/log/level.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#pragma once

#include <log/env.hpp>

#include <stdx/type_traits.hpp>

#include <array>
#include <cstdint>
#include <string_view>
#include <type_traits>
#include <utility>

namespace logging {
// enum assignment is according to Mipi_Sys-T Severity definition
Expand All @@ -30,5 +33,12 @@ template <level L>
return level_text[stdx::to_underlying(L)];
}

template <level L> struct level_constant : std::integral_constant<level, L> {};
[[maybe_unused]] constexpr inline struct get_level_t {
template <typename T>
CONSTEVAL auto operator()(T &&t) const noexcept(
noexcept(std::forward<T>(t).query(std::declval<get_level_t>())))
-> decltype(std::forward<T>(t).query(*this)) {
return std::forward<T>(t).query(*this);
}
} get_level;
} // namespace logging
33 changes: 20 additions & 13 deletions include/log/log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace logging {
namespace null {
struct config {
struct {
template <level, typename>
template <typename>
constexpr auto log(auto &&...) const noexcept -> void {}
} logger;
};
Expand All @@ -46,33 +46,39 @@ ALWAYS_INLINE constexpr static auto get_config() -> auto & {
}
}

template <typename Flavor, level L, typename Env, typename... Ts,
typename... TArgs>
template <typename Flavor, typename Env, typename... Ts, typename... TArgs>
ALWAYS_INLINE static auto log(TArgs &&...args) -> void {
auto &cfg = get_config<Flavor, Ts...>();
cfg.logger.template log<L, Env>(std::forward<TArgs>(args)...);
cfg.logger.template log<Env>(std::forward<TArgs>(args)...);
}
} // namespace logging

// NOLINTBEGIN(cppcoreguidelines-macro-usage)

#define CIB_LOG(FLAVOR, LEVEL, MSG, ...) \
logging::log<FLAVOR, LEVEL, cib_log_env_t>( \
#define CIB_LOG(FLAVOR, MSG, ...) \
logging::log<FLAVOR, cib_log_env_t>( \
__FILE__, __LINE__, sc::format(MSG##_sc __VA_OPT__(, ) __VA_ARGS__))

#define CIB_LOG_WITH_LEVEL(LEVEL, ...) \
do { \
CIB_LOG_ENV(logging::get_level, LEVEL); \
CIB_LOG(logging::default_flavor_t __VA_OPT__(, ) __VA_ARGS__); \
} while (false)

#define CIB_TRACE(...) \
CIB_LOG(logging::default_flavor_t, logging::level::TRACE, __VA_ARGS__)
CIB_LOG_WITH_LEVEL(logging::level::TRACE __VA_OPT__(, ) __VA_ARGS__)
#define CIB_INFO(...) \
CIB_LOG(logging::default_flavor_t, logging::level::INFO, __VA_ARGS__)
CIB_LOG_WITH_LEVEL(logging::level::INFO __VA_OPT__(, ) __VA_ARGS__)
#define CIB_WARN(...) \
CIB_LOG(logging::default_flavor_t, logging::level::WARN, __VA_ARGS__)
CIB_LOG_WITH_LEVEL(logging::level::WARN __VA_OPT__(, ) __VA_ARGS__)
#define CIB_ERROR(...) \
CIB_LOG(logging::default_flavor_t, logging::level::ERROR, __VA_ARGS__)
CIB_LOG_WITH_LEVEL(logging::level::ERROR __VA_OPT__(, ) __VA_ARGS__)

#define CIB_FATAL(MSG, ...) \
[](auto &&str) { \
logging::log<logging::default_flavor_t, logging::level::FATAL, \
cib_log_env_t>(__FILE__, __LINE__, str); \
CIB_LOG_ENV(logging::get_level, logging::level::FATAL); \
logging::log<logging::default_flavor_t, cib_log_env_t>(__FILE__, \
__LINE__, str); \
FWD(str).apply([]<typename S, typename... Args>(S s, Args... args) { \
constexpr auto cts = stdx::ct_string_from_type(s); \
stdx::panic<cts>(args...); \
Expand All @@ -93,7 +99,8 @@ ALWAYS_INLINE static auto log_version() -> void {
}) {
l_cfg.logger.template log_build<v_cfg.build_id, v_cfg.version_string>();
} else {
l_cfg.logger.template log<level::MAX, cib_log_env_t>(
CIB_LOG_ENV(logging::get_level, logging::level::MAX);
l_cfg.logger.template log<cib_log_env_t>(
"", 0,
sc::format("Version: {} ({})"_sc, sc::uint_<v_cfg.build_id>,
stdx::ct_string_to_type<v_cfg.version_string,
Expand Down
8 changes: 4 additions & 4 deletions test/flow/custom_log_levels.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <cib/cib.hpp>
#include <flow/flow.hpp>
#include <log/level.hpp>

#include <catch2/catch_test_macros.hpp>

Expand Down Expand Up @@ -37,11 +38,10 @@ constexpr auto msB = flow::milestone<"msB">();

struct log_config {
struct log_handler {
template <logging::level Level, typename ModuleId,
typename FilenameStringType, typename LineNumberType,
typename MsgType>
template <typename Env, typename FilenameStringType,
typename LineNumberType, typename MsgType>
auto log(FilenameStringType, LineNumberType, MsgType const &) -> void {
log_calls.push_back(Level);
log_calls.push_back(logging::get_level(Env{}).value);
}
};
log_handler logger;
Expand Down
8 changes: 4 additions & 4 deletions test/flow/log_levels.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <cib/cib.hpp>
#include <flow/flow.hpp>
#include <log/level.hpp>

#include <catch2/catch_test_macros.hpp>

Expand Down Expand Up @@ -34,11 +35,10 @@ constexpr auto ms = flow::milestone<"ms">();

struct log_config {
struct log_handler {
template <logging::level Level, typename ModuleId,
typename FilenameStringType, typename LineNumberType,
typename MsgType>
template <typename Env, typename FilenameStringType,
typename LineNumberType, typename MsgType>
auto log(FilenameStringType, LineNumberType, MsgType const &) -> void {
log_calls.push_back(Level);
log_calls.push_back(logging::get_level(Env{}).value);
}
};
log_handler logger;
Expand Down
9 changes: 8 additions & 1 deletion test/log/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
add_tests(FILES log module_id env LIBRARIES cib_log)
add_tests(
FILES
level
log
module_id
env
LIBRARIES
cib_log)
add_tests(FILES fmt_logger LIBRARIES cib_log_fmt)
add_tests(FILES mipi_encoder mipi_logger LIBRARIES cib_log_mipi)

Expand Down
30 changes: 17 additions & 13 deletions test/log/catalog1_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct test_log_args_destination {
last_header = hdr;
}
};

using log_env1 = logging::make_env_t<logging::get_level, logging::level::TRACE>;
} // namespace

auto log_zero_args() -> void;
Expand All @@ -27,32 +29,34 @@ auto log_with_fixed_module_id() -> void;

auto log_zero_args() -> void {
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<logging::level::TRACE, cib_log_env_t>(
"A string with no placeholders"_sc);
cfg.logger.log_msg<log_env1>("A string with no placeholders"_sc);
}

auto log_one_ct_arg() -> void {
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<logging::level::TRACE, cib_log_env_t>(
cfg.logger.log_msg<log_env1>(
format("B string with {} placeholder"_sc, "one"_sc));
}

auto log_one_rt_arg() -> void {
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<logging::level::TRACE, cib_log_env_t>(
format("C string with {} placeholder"_sc, 1));
cfg.logger.log_msg<log_env1>(format("C string with {} placeholder"_sc, 1));
}

auto log_with_non_default_module_id() -> void {
CIB_LOG_MODULE("not default");
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<logging::level::TRACE, cib_log_env_t>(
format("ModuleID string with {} placeholder"_sc, 1));
CIB_WITH_LOG_ENV(logging::get_level, logging::level::TRACE,
logging::get_module, "not default") {
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<cib_log_env_t>(
format("ModuleID string with {} placeholder"_sc, 1));
}
}

auto log_with_fixed_module_id() -> void {
CIB_LOG_MODULE("fixed");
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<logging::level::TRACE, cib_log_env_t>(
format("Fixed ModuleID string with {} placeholder"_sc, 1));
CIB_WITH_LOG_ENV(logging::get_level, logging::level::TRACE,
logging::get_module, "fixed") {
auto cfg = logging::mipi::config{test_log_args_destination{}};
cfg.logger.log_msg<cib_log_env_t>(
format("Fixed ModuleID string with {} placeholder"_sc, 1));
}
}
Loading

0 comments on commit 903437b

Please sign in to comment.