diff --git a/CMakeLists.txt b/CMakeLists.txt index bab5bf77..c67ea635 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,13 +193,13 @@ target_sources( FILES include/log/fmt/logger.hpp) -add_library(cib_log_mipi INTERFACE) -target_compile_features(cib_log_mipi INTERFACE cxx_std_20) -target_link_libraries_system(cib_log_mipi INTERFACE cib_log cib_msg concurrency - stdx) +add_library(cib_log_binary INTERFACE) +target_compile_features(cib_log_binary INTERFACE cxx_std_20) +target_link_libraries_system(cib_log_binary INTERFACE cib_log cib_msg + concurrency stdx) target_sources( - cib_log_mipi + cib_log_binary INTERFACE FILE_SET log TYPE @@ -208,8 +208,8 @@ target_sources( include FILES include/log/catalog/catalog.hpp + include/log/catalog/encoder.hpp include/log/catalog/mipi_builder.hpp - include/log/catalog/mipi_encoder.hpp include/log/catalog/mipi_messages.hpp) add_library(cib_nexus INTERFACE) @@ -298,8 +298,8 @@ target_link_libraries_system( cib_flow cib_interrupt cib_log + cib_log_binary cib_log_fmt - cib_log_mipi cib_lookup cib_match cib_msg @@ -329,8 +329,8 @@ if(PROJECT_IS_TOP_LEVEL) clang_tidy_interface(cib_interrupt) clang_tidy_interface(cib_lookup) clang_tidy_interface(cib_log) + clang_tidy_interface(cib_log_binary) clang_tidy_interface(cib_log_fmt) - clang_tidy_interface(cib_log_mipi) clang_tidy_interface(cib_match) clang_tidy_interface(cib_msg) clang_tidy_interface(cib_nexus) diff --git a/docs/intro.adoc b/docs/intro.adoc index f43bc416..2e657ca5 100644 --- a/docs/intro.adoc +++ b/docs/intro.adoc @@ -73,8 +73,8 @@ flowchart BT msg(cib_msg) --> log & match msg --> lookup - log_mipi(cib_log_mipi) --> msg + log_binary(cib_log_binary) --> msg seq(cib_seq) --> flow - cib --> interrupt & seq & log_fmt & log_mipi + cib --> interrupt & seq & log_fmt & log_binary ---- diff --git a/docs/logging.adoc b/docs/logging.adoc index afa24145..aa8e2f0d 100644 --- a/docs/logging.adoc +++ b/docs/logging.adoc @@ -14,7 +14,7 @@ Logging in _cib_ is in two parts: Three possible logger implementations are provided: - one using fmt in https://github.com/intel/compile-time-init-build/tree/main/include/log/fmt/logger.hpp[fmt/logger.hpp] -- one using the https://www.mipi.org/specifications/sys-t[MIPI Sys-T spec] in https://github.com/intel/compile-time-init-build/tree/main/include/log/catalog/mipi_encoder.hpp[catalog/mipi_encoder.hpp] +- one using binary encoding in https://github.com/intel/compile-time-init-build/tree/main/include/log/catalog/encoder.hpp[catalog/encoder.hpp], using the https://www.mipi.org/specifications/sys-t[MIPI Sys-T spec] by default - the default implementation: the null logger which accepts everything, but never produces output === Log levels @@ -208,14 +208,14 @@ template <> inline auto version::config<> = my_version_config{}; ---- Then use `CIB_LOG_VERSION()` to log the version. If the logging config provides -a `log_build` function, that will be used. Otherwise a text string will be +a `log_version` function, that will be used. Otherwise a text string will be logged. [source,cpp] ---- struct my_logger_config { struct { - template auto log_build() -> void { + template auto log_version() -> void { // log the build version according to my mechanism } } logger; @@ -223,7 +223,7 @@ struct my_logger_config { template <> inline auto logging::config<> = my_logger_config{}; -CIB_LOG_VERSION(); // calls my_logger_config::log_build +CIB_LOG_VERSION(); // calls my_logger_config::log_version ---- The easiest way to flavor the version logging is to define a macro in terms of diff --git a/docs/sc.adoc b/docs/sc.adoc index b14c995f..b5e5b29e 100644 --- a/docs/sc.adoc +++ b/docs/sc.adoc @@ -43,7 +43,7 @@ static_assert("Hello,"_sc + " World!"_sc == "Hello, World!"_sc); The reason `string_constant` exists is for efficient logging. On a constrained system, space for text can be limited-to-nonexistent. `string_constant` interacts with the -https://github.com/intel/compile-time-init-build/tree/main/include/log/catalog/mipi_encoder.hpp[MIPI +https://github.com/intel/compile-time-init-build/tree/main/include/log/catalog/encoder.hpp[MIPI Sys-T logging config] to solve this problem. - First, each `string_constant` contains string character data in its type. diff --git a/include/log/README.md b/include/log/README.md index ad18cc08..a3d658fe 100644 --- a/include/log/README.md +++ b/include/log/README.md @@ -6,7 +6,7 @@ Logging in *cib* is in two parts: Three possible logger implementations are provided: - one using libfmt in [fmt/logger.hpp](fmt/logger.hpp) -- one using the [MIPI SyS-T spec](https://www.mipi.org/specifications/sys-t), in [catalog/mipi_encoder.hpp](catalog/mipi_encoder.hpp) +- a binary logger in [catalog/encoder.hpp](catalog/encoder.hpp), by default using the [MIPI SyS-T spec](https://www.mipi.org/specifications/sys-t) - the null logger (accepts everything, never produces output) ## log levels diff --git a/include/log/catalog/builder.hpp b/include/log/catalog/builder.hpp new file mode 100644 index 00000000..8a05bf3d --- /dev/null +++ b/include/log/catalog/builder.hpp @@ -0,0 +1,21 @@ +#include + +#include + +#include + +namespace logging::binary { +[[maybe_unused]] constexpr inline struct get_builder_t { + template + requires true + CONSTEVAL auto operator()(T &&t) const noexcept( + noexcept(std::forward(t).query(std::declval()))) + -> decltype(std::forward(t).query(*this)) { + return std::forward(t).query(*this); + } + + CONSTEVAL auto operator()(auto &&) const { + return logging::mipi::default_builder{}; + } +} get_builder; +} // namespace logging::binary diff --git a/include/log/catalog/encoder.hpp b/include/log/catalog/encoder.hpp new file mode 100644 index 00000000..0357bfe0 --- /dev/null +++ b/include/log/catalog/encoder.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace logging::binary { +namespace detail { +template constexpr static auto to_message() { + constexpr auto s = S::value; + using char_t = typename std::remove_cv_t::value_type; + return [&](std::integer_sequence) { + return sc::message< + sc::undefined, char_t, s[Is]...>>{}; + }(std::make_integer_sequence{}); +} + +template constexpr static auto to_module() { + constexpr auto s = std::string_view{S}; + return [&](std::integer_sequence) { + return sc::module_string>{}; + }(std::make_integer_sequence{}); +} + +template struct to_message_t { + template using fn = decltype(to_message()); +}; +} // namespace detail + +template struct log_writer { + template + auto operator()(stdx::span msg) -> void { + stdx::for_each( + [&](Dest &dest) { + conc::call_in_critical_section( + [&] { dest.log_by_buf(msg); }); + }, + dests); + } + + template + auto operator()(stdx::span msg) -> void { + [&](std::index_sequence) { + stdx::for_each( + [&](Dest &dest) { + conc::call_in_critical_section( + [&] { dest.log_by_args(msg[Is]...); }); + }, + dests); + }(std::make_index_sequence{}); + } + + auto operator()(auto const &msg) -> void { + this->operator()(msg.as_const_view().data()); + } + + Destinations dests; +}; +template log_writer(T) -> log_writer; + +template struct log_handler { + template + auto log(FilenameStringType, LineNumberType, MsgType const &msg) -> void { + log_msg(msg); + } + + template auto log_msg(Msg msg) -> void { + msg.apply([&](S, Args... args) { + auto builder = get_builder(Env{}); + constexpr auto L = stdx::to_underlying(get_level(Env{})); + using Message = typename decltype(builder)::template convert_args< + detail::to_message_t::template fn, Args...>; + using Module = decltype(detail::to_module()); + w(builder.template build(catalog(), module(), + args...)); + }); + } + + template + auto log_version() -> void { + auto builder = get_builder(Env{}); + w(builder.template build_version()); + } + + Writer w; +}; + +template struct config { + using destinations_tuple_t = stdx::tuple; + constexpr explicit config(TDestinations... dests) + : logger{log_writer{stdx::tuple{std::move(dests)...}}} {} + + log_handler> logger; +}; +template config(Ts...) -> config; +} // namespace logging::binary diff --git a/include/log/catalog/mipi_builder.hpp b/include/log/catalog/mipi_builder.hpp index 476b417f..bcd3f4fe 100644 --- a/include/log/catalog/mipi_builder.hpp +++ b/include/log/catalog/mipi_builder.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,40 @@ template <> struct builder { } }; +template <> struct builder { + template static auto build() { + using namespace msg; + return owning{"build_id"_field = Version}; + } +}; + +template <> struct builder { + template static auto build() { + using namespace msg; + return owning{"build_id"_field = Version}; + } +}; + +template <> struct builder { + template static auto build() { + using namespace msg; + constexpr auto header_size = + defn::normal_build_msg_t::size::value; + constexpr auto payload_len = S.size() + sizeof(std::uint64_t); + using storage_t = std::array; + + defn::normal_build_msg_t::owner_t message{ + "payload_len"_field = payload_len}; + auto dest = &message.data()[header_size]; + + auto const ver = stdx::to_le(static_cast(Version)); + dest = std::copy_n(stdx::bit_cast(&ver), + sizeof(std::uint64_t), dest); + std::copy_n(std::cbegin(S.value), S.size(), dest); + return message; + } +}; + struct default_builder { template static auto build(string_id id, module_id m, Ts... args) { @@ -121,17 +156,22 @@ struct default_builder { id, m, args...); } } -}; -[[maybe_unused]] constexpr inline struct get_builder_t { - template - requires true - CONSTEVAL auto operator()(T &&t) const noexcept( - noexcept(std::forward(t).query(std::declval()))) - -> decltype(std::forward(t).query(*this)) { - return std::forward(t).query(*this); + template auto build_version() { + using namespace msg; + if constexpr (S.empty() and stdx::bit_width(Version) <= 22) { + return builder{} + .template build(); + } else if constexpr (S.empty() and stdx::bit_width(Version) <= 54) { + return builder{} + .template build(); + } else { + return builder{} + .template build(); + } } - CONSTEVAL auto operator()(auto &&) const { return default_builder{}; } -} get_builder; + template