diff --git a/CMakeLists.txt b/CMakeLists.txt index d857c98e..b037a34f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,10 +188,16 @@ target_sources( BASE_DIRS include FILES + include/log/module_id.hpp + include/log/string_id.hpp + include/log/unit.hpp + include/log/catalog/arguments.hpp + include/log/catalog/builder.hpp include/log/catalog/catalog.hpp include/log/catalog/encoder.hpp include/log/catalog/mipi_builder.hpp - include/log/catalog/mipi_messages.hpp) + include/log/catalog/mipi_messages.hpp + include/log/catalog/writer.hpp) add_library(cib_nexus INTERFACE) target_compile_features(cib_nexus INTERFACE cxx_std_20) diff --git a/docs/logging.adoc b/docs/logging.adoc index fa57b673..43d07e70 100644 --- a/docs/logging.adoc +++ b/docs/logging.adoc @@ -221,6 +221,38 @@ wrapper function (`gen_str_catalog`)] that drives the process. See https://github.com/intel/compile-time-init-build/blob/main/test/CMakeLists.txt[the test] that exercises that functionality for an example. +`gen_str_catalog` is the CMake function that drives the string catalog generation. + +[source,cpp] +---- +gen_str_catalog( + GEN_STR_CATALOG + OUTPUT_CPP + OUTPUT_JSON + OUTPUT_XML + INPUT_LIBS + INPUT_JSON + STABLE_JSON + INPUT_HEADERS + CLIENT_NAME + VERSION + GUID_ID + GUID_MASK + MODULE_ID_MAX + OUTPUT_LIB + OUTPUTS_TARGET + FORGET_OLD_IDS) +---- +- `INPUT_LIBS` is a required argument: this will be the input libraries from which the undefined symbols are extracted. +- `OUTPUT_{CPP,JSON,XML}` are the generated files. Also required. +- `INPUT_JSON` is optional extra JSON that will be copied verbatim into the generated JSON. +- `STABLE_JSON` is optional information about stable string and module IDs -- for example, from a previous build. +- `CLIENT_NAME`, `VERSION`, `GUID_ID` and `GUID_MASK` are all optional input fields for the MIPI-SyS-T XML. +- `MODULE_ID_MAX` is an optional upper bound on the assigned module IDs. This is useful to limit module ID bit-space. +- `OUTPUT_LIB` is an optional (`STATIC`) library target consisting of the `OUTPUT_CPP` file. +- `FORGET_OLD_IDS` is optional, and if present disregards the `STABLE_JSON` information. +- `GEN_STR_CATALOG` is optional, and allows pointing to a different python script. + === Implementing a logger Each logging implementation (configuration) provides a customization point: a @@ -458,3 +490,20 @@ CIB_TRACE("Hello"); See the https://www.mipi.org/specifications/sys-t[MIPI Sys-T spec] for more details. + +=== Examples/How-Tos + +I want to... + +- ...use the fmt logger... + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/fmt_normal[...as my normal logger] + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/fmt_tests[...in tests, to make sure my code logs correctly] + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/fmt_multi[...to output to multiple places (stdout, file, etc)] + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/fmt_custom_level[...with a custom level enumeration] +- ...use the binary logger... + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/binary_normal[...as my normal logger] + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/binary_custom[...with my own binary format] + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/binary_stable_ids[...and keep string IDs stable from build to build] + * https://github.com/intel/compile-time-init-build/tree/main/examples/log/binary_fixed_id[...and fix a string ID in code] +- https://github.com/intel/compile-time-init-build/tree/main/examples/log/custom[...use my own logger] +- https://github.com/intel/compile-time-init-build/tree/main/examples/log/secure[...use a secure logger as well as a "normal" one] diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f25aca11..c8f1d75b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,14 +1,23 @@ add_custom_target(examples) +function(transform_to_example VAR VALUE) + cmake_path(GET CMAKE_CURRENT_LIST_DIR PARENT_PATH pp) + cmake_path(GET pp FILENAME prefix) + string(PREPEND VALUE "EXAMPLE.${prefix}.") + set(${VAR} + ${VALUE} + PARENT_SCOPE) +endfunction() + function(add_example) set(singleValueArgs NAME) - set(multiValueArgs FILES) + set(multiValueArgs FILES LIBS) cmake_parse_arguments(EX "" "${singleValueArgs}" "${multiValueArgs}" ${ARGN}) - string(PREPEND EX_NAME "EXAMPLE.") + transform_to_example(EX_NAME ${EX_NAME}) add_executable(${EX_NAME} ${EX_FILES}) - target_link_libraries(${EX_NAME} cib) + target_link_libraries(${EX_NAME} ${EX_LIBS}) add_dependencies(examples ${EX_NAME}) endfunction() diff --git a/examples/flow/daily_routine/CMakeLists.txt b/examples/flow/daily_routine/CMakeLists.txt index 01878dbe..3acabf67 100644 --- a/examples/flow/daily_routine/CMakeLists.txt +++ b/examples/flow/daily_routine/CMakeLists.txt @@ -32,7 +32,7 @@ if(NOT TARGET cib) endif() if(COMMAND add_example) - add_example(NAME daily_routine FILES main.cpp) + add_example(NAME daily_routine FILES main.cpp LIBS cib) else() add_executable(daily_routine main.cpp) target_link_libraries(daily_routine cib) diff --git a/examples/log/CMakeLists.txt b/examples/log/CMakeLists.txt index 8b137891..b833f87b 100644 --- a/examples/log/CMakeLists.txt +++ b/examples/log/CMakeLists.txt @@ -1 +1,12 @@ +add_subdirectory(fmt_custom_level) +add_subdirectory(fmt_multi) +add_subdirectory(fmt_normal) +add_subdirectory(fmt_tests) +add_subdirectory(binary_custom) +add_subdirectory(binary_fixed_id) +add_subdirectory(binary_stable_ids) +add_subdirectory(binary_normal) + +add_subdirectory(custom) +add_subdirectory(secure) diff --git a/examples/log/binary_custom/CMakeLists.txt b/examples/log/binary_custom/CMakeLists.txt new file mode 100644 index 00000000..0efd0b0b --- /dev/null +++ b/examples/log/binary_custom/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.25) + +project(binary_custom LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + transform_to_example(binary_custom_lib binary_custom_lib) + transform_to_example(binary_custom_strings_lib binary_custom_strings_lib) + transform_to_example(binary_custom binary_custom) +else() + set(binary_custom_lib binary_custom_lib) + set(binary_custom_strings_lib binary_custom_strings_lib) + set(binary_custom binary_custom) +endif() + +# build the bulk of the code as a library +add_library(${binary_custom_lib} lib.cpp) +target_link_libraries(${binary_custom_lib} PRIVATE cib_log_binary) + +# generate the strings from that library +gen_str_catalog( + OUTPUT_CPP + ${CMAKE_CURRENT_BINARY_DIR}/strings.cpp + OUTPUT_JSON + ${CMAKE_CURRENT_BINARY_DIR}/strings.json + OUTPUT_XML + ${CMAKE_CURRENT_BINARY_DIR}/strings.xml + INPUT_LIBS + ${binary_custom_lib} + OUTPUT_LIB + ${binary_custom_strings_lib}) + +# link a stub executable with the "main" library and the strings library +add_executable(${binary_custom} main.cpp) +target_link_libraries(${binary_custom} ${binary_custom_lib} + ${binary_custom_strings_lib}) diff --git a/examples/log/binary_custom/lib.cpp b/examples/log/binary_custom/lib.cpp new file mode 100644 index 00000000..433b3094 --- /dev/null +++ b/examples/log/binary_custom/lib.cpp @@ -0,0 +1,9 @@ +#include "logger.hpp" + +namespace lib { + +// Provide an environment for this scope that uses our builder. +CIB_LOG_ENV(logging::binary::get_builder, custom::builder{}); + +auto lib_func() -> void { CIB_INFO("Hello"); } +} // namespace lib diff --git a/examples/log/binary_custom/logger.hpp b/examples/log/binary_custom/logger.hpp new file mode 100644 index 00000000..4a1d2e5d --- /dev/null +++ b/examples/log/binary_custom/logger.hpp @@ -0,0 +1,55 @@ +// include the binary logger and message machinery +#include +#include + +#include + +#include +#include +#include + +namespace custom { +namespace defn { +using msg::at; +using msg::dword_index_t; +using msg::field; +using msg::message; +using msg::operator""_msb; +using msg::operator""_lsb; + +// Define a message type for the custom binary format. +// For simplicity, this message is just the 32-bit string ID. +using id_f = + field<"id", std::uint32_t>::located; +using id_msg_t = message<"id", id_f>; +} // namespace defn + +// Provide a builder: a structure with a build function that takes +// various arguments and returns an (owning) message. +struct builder : logging::mipi::default_builder<> { + template + static auto build(string_id, module_id, logging::mipi::unit_t, Ts...) { + using namespace msg; + return owning{"id"_field = 42}; + } +}; + +// Provide a destination: a structure with a call operator that takes a +// stdx::span. +struct log_destination { + template + auto operator()(stdx::span packet) const { + // write the binary log packet somewhere... + std::cout << "Got a binary log packet, string ID: " << packet[0] + << '\n'; + ; + } +}; +} // namespace custom + +// Specialize the logging config variable template to use the binary logger with +// a destination. +// Remember: each translation unit that logs must see this same specialization! +template <> +inline auto logging::config<> = + logging::binary::config{custom::log_destination{}}; diff --git a/examples/log/binary_custom/main.cpp b/examples/log/binary_custom/main.cpp new file mode 100644 index 00000000..c2386738 --- /dev/null +++ b/examples/log/binary_custom/main.cpp @@ -0,0 +1,7 @@ +// the "main" application is a stub that calls into the library code + +namespace lib { +auto lib_func() -> void; +} + +auto main() -> int { lib::lib_func(); } diff --git a/examples/log/binary_fixed_id/CMakeLists.txt b/examples/log/binary_fixed_id/CMakeLists.txt new file mode 100644 index 00000000..81d730f9 --- /dev/null +++ b/examples/log/binary_fixed_id/CMakeLists.txt @@ -0,0 +1,65 @@ +cmake_minimum_required(VERSION 3.25) + +project(binary_fixed_id LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + transform_to_example(binary_fixed_id_lib binary_fixed_id_lib) + transform_to_example(binary_fixed_id_strings_lib + binary_fixed_id_strings_lib) + transform_to_example(binary_fixed_id binary_fixed_id) +else() + set(binary_fixed_id_lib binary_fixed_id_lib) + set(binary_fixed_id_strings_lib binary_fixed_id_strings_lib) + set(binary_fixed_id binary_fixed_id) +endif() + +# build the bulk of the code as a library +add_library(${binary_fixed_id_lib} lib.cpp) +target_link_libraries(${binary_fixed_id_lib} PRIVATE cib_log_binary) + +# generate the strings from that library +gen_str_catalog( + OUTPUT_CPP + ${CMAKE_CURRENT_BINARY_DIR}/strings.cpp + OUTPUT_JSON + ${CMAKE_CURRENT_BINARY_DIR}/strings.json + OUTPUT_XML + ${CMAKE_CURRENT_BINARY_DIR}/strings.xml + INPUT_LIBS + ${binary_fixed_id_lib} + OUTPUT_LIB + ${binary_fixed_id_strings_lib}) + +# link a stub executable with the "main" library and the strings library +add_executable(${binary_fixed_id} main.cpp) +target_link_libraries(${binary_fixed_id} ${binary_fixed_id_lib} + ${binary_fixed_id_strings_lib}) diff --git a/examples/log/binary_fixed_id/lib.cpp b/examples/log/binary_fixed_id/lib.cpp new file mode 100644 index 00000000..a3256d12 --- /dev/null +++ b/examples/log/binary_fixed_id/lib.cpp @@ -0,0 +1,8 @@ +#include "logger.hpp" + +auto lib_func() -> void { + // For this specific log call, fix the string ID to 1337 + CIB_WITH_LOG_ENV(logging::get_string_id, 1337) { CIB_INFO("Hello"); } + // The same technique can be used to fix any particular attribute query for + // a single call. +} diff --git a/examples/log/binary_fixed_id/logger.hpp b/examples/log/binary_fixed_id/logger.hpp new file mode 100644 index 00000000..1958529d --- /dev/null +++ b/examples/log/binary_fixed_id/logger.hpp @@ -0,0 +1,29 @@ +// include the binary logger +#include + +#include + +#include +#include +#include + +namespace custom { +// Provide a destination: a structure with a call operator that takes a +// stdx::span. +struct log_destination { + template + auto operator()(stdx::span packet) const { + using namespace msg; + const_view m{packet}; + std::cout << "Got a binary log packet, string ID: " + << m.get("payload"_field) << '\n'; + } +}; +} // namespace custom + +// specialize the logging config variable template to use the binary logger with +// a destination +// remember: each translation unit that logs must see this same specialization! +template <> +inline auto logging::config<> = + logging::binary::config{custom::log_destination{}}; diff --git a/examples/log/binary_fixed_id/main.cpp b/examples/log/binary_fixed_id/main.cpp new file mode 100644 index 00000000..0132ce2c --- /dev/null +++ b/examples/log/binary_fixed_id/main.cpp @@ -0,0 +1,5 @@ +// the "main" application is a stub that calls into the library code + +auto lib_func() -> void; + +auto main() -> int { lib_func(); } diff --git a/examples/log/binary_normal/CMakeLists.txt b/examples/log/binary_normal/CMakeLists.txt new file mode 100644 index 00000000..70bc6dde --- /dev/null +++ b/examples/log/binary_normal/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.25) + +project(binary_normal LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + transform_to_example(binary_normal_lib binary_normal_lib) + transform_to_example(binary_normal_strings_lib binary_normal_strings_lib) + transform_to_example(binary_normal binary_normal) +else() + set(binary_normal_lib binary_normal_lib) + set(binary_normal_strings_lib binary_normal_strings_lib) + set(binary_normal binary_normal) +endif() + +# build the bulk of the code as a library +add_library(${binary_normal_lib} lib.cpp) +target_link_libraries(${binary_normal_lib} PRIVATE cib_log_binary) + +# generate the strings from that library +gen_str_catalog( + OUTPUT_CPP + ${CMAKE_CURRENT_BINARY_DIR}/strings.cpp + OUTPUT_JSON + ${CMAKE_CURRENT_BINARY_DIR}/strings.json + OUTPUT_XML + ${CMAKE_CURRENT_BINARY_DIR}/strings.xml + INPUT_LIBS + ${binary_normal_lib} + OUTPUT_LIB + ${binary_normal_strings_lib}) + +# link a stub executable with the "main" library and the strings library +add_executable(${binary_normal} main.cpp) +target_link_libraries(${binary_normal} ${binary_normal_lib} + ${binary_normal_strings_lib}) diff --git a/examples/log/binary_normal/lib.cpp b/examples/log/binary_normal/lib.cpp new file mode 100644 index 00000000..f9b8742d --- /dev/null +++ b/examples/log/binary_normal/lib.cpp @@ -0,0 +1,4 @@ +#include "logger.hpp" + +// logs will now use the binary logger and go to our destination +auto lib_func() -> void { CIB_INFO("Hello"); } diff --git a/examples/log/binary_normal/logger.hpp b/examples/log/binary_normal/logger.hpp new file mode 100644 index 00000000..e1593c83 --- /dev/null +++ b/examples/log/binary_normal/logger.hpp @@ -0,0 +1,34 @@ +// include the binary logger +#include + +#include + +#include +#include +#include + +namespace custom { +// Provide a destination: a structure with a call operator that takes a +// stdx::span. +struct log_destination { + // The call operator can be a function template, in which case we will get + // an instantiation for each span size (roughly corresponding to number of + // runtime log arguments). + template + auto operator()(stdx::span packet) const { + // write the binary log packet somewhere... + std::cout << "Got a binary log packet\n"; + } + + // Or the call operator can take a dynamic-sized span + // auto operator()(stdx::span packet) const { + // } +}; +} // namespace custom + +// specialize the logging config variable template to use the binary logger with +// a destination +// remember: each translation unit that logs must see this same specialization! +template <> +inline auto logging::config<> = + logging::binary::config{custom::log_destination{}}; diff --git a/examples/log/binary_normal/main.cpp b/examples/log/binary_normal/main.cpp new file mode 100644 index 00000000..0132ce2c --- /dev/null +++ b/examples/log/binary_normal/main.cpp @@ -0,0 +1,5 @@ +// the "main" application is a stub that calls into the library code + +auto lib_func() -> void; + +auto main() -> int { lib_func(); } diff --git a/examples/log/binary_stable_ids/CMakeLists.txt b/examples/log/binary_stable_ids/CMakeLists.txt new file mode 100644 index 00000000..f602be17 --- /dev/null +++ b/examples/log/binary_stable_ids/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.25) + +project(binary_stable_ids LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + transform_to_example(binary_stable_ids_lib binary_stable_ids_lib) + transform_to_example(binary_stable_ids_strings_lib + binary_stable_ids_strings_lib) + transform_to_example(binary_stable_ids binary_stable_ids) +else() + set(binary_stable_ids_lib binary_stable_ids_lib) + set(binary_stable_ids_strings_lib binary_stable_ids_strings_lib) + set(binary_stable_ids binary_stable_ids) +endif() + +# build the bulk of the code as a library +add_library(${binary_stable_ids_lib} lib.cpp) +target_link_libraries(${binary_stable_ids_lib} PRIVATE cib_log_binary) + +# generate the strings from that library, supplying a stable_strings.json file +# to keep matching strings stable. stable_strings.json could be the strings.json +# output from the last build. It could also contain manually reserved/fixed IDs. +gen_str_catalog( + OUTPUT_CPP + ${CMAKE_CURRENT_BINARY_DIR}/strings.cpp + OUTPUT_JSON + ${CMAKE_CURRENT_BINARY_DIR}/strings.json + OUTPUT_XML + ${CMAKE_CURRENT_BINARY_DIR}/strings.xml + INPUT_LIBS + ${binary_stable_ids_lib} + STABLE_JSON + stable_strings.json + OUTPUT_LIB + ${binary_stable_ids_strings_lib}) + +# link a stub executable with the "main" library and the strings library +add_executable(${binary_stable_ids} main.cpp) +target_link_libraries(${binary_stable_ids} ${binary_stable_ids_lib} + ${binary_stable_ids_strings_lib}) diff --git a/examples/log/binary_stable_ids/lib.cpp b/examples/log/binary_stable_ids/lib.cpp new file mode 100644 index 00000000..39ea357f --- /dev/null +++ b/examples/log/binary_stable_ids/lib.cpp @@ -0,0 +1,5 @@ +#include "logger.hpp" + +// logs will have the ID assigned by gen_str_catalog, taking into account the +// stable input +auto lib_func() -> void { CIB_INFO("Hello"); } diff --git a/examples/log/binary_stable_ids/logger.hpp b/examples/log/binary_stable_ids/logger.hpp new file mode 100644 index 00000000..1958529d --- /dev/null +++ b/examples/log/binary_stable_ids/logger.hpp @@ -0,0 +1,29 @@ +// include the binary logger +#include + +#include + +#include +#include +#include + +namespace custom { +// Provide a destination: a structure with a call operator that takes a +// stdx::span. +struct log_destination { + template + auto operator()(stdx::span packet) const { + using namespace msg; + const_view m{packet}; + std::cout << "Got a binary log packet, string ID: " + << m.get("payload"_field) << '\n'; + } +}; +} // namespace custom + +// specialize the logging config variable template to use the binary logger with +// a destination +// remember: each translation unit that logs must see this same specialization! +template <> +inline auto logging::config<> = + logging::binary::config{custom::log_destination{}}; diff --git a/examples/log/binary_stable_ids/main.cpp b/examples/log/binary_stable_ids/main.cpp new file mode 100644 index 00000000..0132ce2c --- /dev/null +++ b/examples/log/binary_stable_ids/main.cpp @@ -0,0 +1,5 @@ +// the "main" application is a stub that calls into the library code + +auto lib_func() -> void; + +auto main() -> int { lib_func(); } diff --git a/examples/log/binary_stable_ids/stable_strings.json b/examples/log/binary_stable_ids/stable_strings.json new file mode 100644 index 00000000..603f9aaa --- /dev/null +++ b/examples/log/binary_stable_ids/stable_strings.json @@ -0,0 +1,18 @@ +{ + "messages": [ + { + "msg": "Hello", + "type": "msg", + "arg_types": [], + "arg_count": 0, + "id": 42 + } + ], + "modules": [ + { + "string": "default", + "id": 0 + } + ], + "enums": {} +} diff --git a/examples/log/custom/CMakeLists.txt b/examples/log/custom/CMakeLists.txt new file mode 100644 index 00000000..58f03eac --- /dev/null +++ b/examples/log/custom/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) + +project(custom LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + add_example(NAME custom FILES main.cpp LIBS cib_log) +else() + add_executable(custom main.cpp) + target_link_libraries(custom cib_log) +endif() diff --git a/examples/log/custom/main.cpp b/examples/log/custom/main.cpp new file mode 100644 index 00000000..09d7e277 --- /dev/null +++ b/examples/log/custom/main.cpp @@ -0,0 +1,29 @@ +#include + +#include +#include + +// Provide a log handler +namespace custom { +struct log_handler { + template + auto log(FilenameStringType f, LineNumberType n, FmtResult const &fr) + -> void { + std::cout << "Log: " << f << ":" << n << ": " + << std::string_view{fr.str.value} << '\n'; + } +}; + +// Provide a log config with that handler +struct config { + log_handler logger; +}; +} // namespace custom + +// specialize the logging config variable template to use the +// custom config +template <> inline auto logging::config<> = custom::config{}; + +// logs will now go to the custom logger +auto main() -> int { CIB_INFO("Hello"); } diff --git a/examples/log/fmt_custom_level/CMakeLists.txt b/examples/log/fmt_custom_level/CMakeLists.txt new file mode 100644 index 00000000..4150edbf --- /dev/null +++ b/examples/log/fmt_custom_level/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) + +project(fmt_custom_level LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + add_example(NAME fmt_custom_level FILES main.cpp LIBS cib_log_fmt) +else() + add_executable(fmt_custom_level main.cpp) + target_link_libraries(fmt_custom_level cib_log_fmt) +endif() diff --git a/examples/log/fmt_custom_level/main.cpp b/examples/log/fmt_custom_level/main.cpp new file mode 100644 index 00000000..b472e3ee --- /dev/null +++ b/examples/log/fmt_custom_level/main.cpp @@ -0,0 +1,41 @@ +// include the fmt logger +#include + +#include +#include + +// custom level enum +namespace custom { +enum struct level : std::uint8_t { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3 }; +} + +// specialize the logging config variable template to use the fmt logger with a +// destination (in this case, std::cout) +// remember: each translation unit that logs must see this same specialization! +template <> +inline auto logging::config<> = + logging::fmt::config{std::ostream_iterator(std::cout)}; + +// tell libfmt how to print our custom level +namespace logging { +template +[[nodiscard]] auto format_as(level_wrapper) -> std::string_view { + switch (L) { + case custom::level::DEBUG: + return "custom_DEBUG"; + case custom::level::INFO: + return "custom_INFO"; + case custom::level::WARN: + return "custom_WARN"; + case custom::level::ERROR: + return "custom_ERROR"; + } +} +} // namespace logging + +// set up our own logging macros that use our custom levels +#define CUSTOM_INFO(...) \ + CIB_LOG_WITH_LEVEL(custom::level::INFO __VA_OPT__(, ) __VA_ARGS__) + +// logs will now use our custom levels +auto main() -> int { CUSTOM_INFO("Hello"); } diff --git a/examples/log/fmt_multi/CMakeLists.txt b/examples/log/fmt_multi/CMakeLists.txt new file mode 100644 index 00000000..3be9fe35 --- /dev/null +++ b/examples/log/fmt_multi/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) + +project(fmt_multi LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + add_example(NAME fmt_multi FILES main.cpp LIBS cib_log_fmt) +else() + add_executable(fmt_multi main.cpp) + target_link_libraries(fmt_multi cib_log_fmt) +endif() diff --git a/examples/log/fmt_multi/main.cpp b/examples/log/fmt_multi/main.cpp new file mode 100644 index 00000000..bcd584d6 --- /dev/null +++ b/examples/log/fmt_multi/main.cpp @@ -0,0 +1,25 @@ +// include the fmt logger +#include + +#include +#include +#include + +namespace { +// here we use the Myers singleton pattern to get an output iterator to a file +// if we need something more flexible, to use the fmt logger we can +// implement an iterator that can be used with fmt::format_to +auto get_file_output() { + static auto f = std::ofstream("log.txt"); + return std::ostream_iterator(f); +} +} // namespace + +// specialize the logging config variable template to use the fmt logger with +// multiple destinations +template <> +inline auto logging::config<> = logging::fmt::config{ + std::ostream_iterator(std::cout), get_file_output()}; + +// logs will now use libfmt and go to both cout and the file +auto main() -> int { CIB_INFO("Hello"); } diff --git a/examples/log/fmt_normal/CMakeLists.txt b/examples/log/fmt_normal/CMakeLists.txt new file mode 100644 index 00000000..93ac5dcd --- /dev/null +++ b/examples/log/fmt_normal/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) + +project(fmt_normal LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + add_example(NAME fmt_normal FILES main.cpp LIBS cib_log_fmt) +else() + add_executable(fmt_normal main.cpp) + target_link_libraries(fmt_normal cib_log_fmt) +endif() diff --git a/examples/log/fmt_normal/main.cpp b/examples/log/fmt_normal/main.cpp new file mode 100644 index 00000000..df09fd09 --- /dev/null +++ b/examples/log/fmt_normal/main.cpp @@ -0,0 +1,15 @@ +// include the fmt logger +#include + +#include +#include + +// specialize the logging config variable template to use the fmt logger with a +// destination (in this case, std::cout) +// remember: each translation unit that logs must see this same specialization! +template <> +inline auto logging::config<> = + logging::fmt::config{std::ostream_iterator(std::cout)}; + +// logs will now use libfmt and go to std::cout +auto main() -> int { CIB_INFO("Hello"); } diff --git a/examples/log/fmt_tests/CMakeLists.txt b/examples/log/fmt_tests/CMakeLists.txt new file mode 100644 index 00000000..f86cd57d --- /dev/null +++ b/examples/log/fmt_tests/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) + +project(fmt_tests LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + add_example(NAME fmt_tests FILES main.cpp LIBS cib_log_fmt) +else() + add_executable(fmt_tests main.cpp) + target_link_libraries(fmt_tests cib_log_fmt) +endif() diff --git a/examples/log/fmt_tests/main.cpp b/examples/log/fmt_tests/main.cpp new file mode 100644 index 00000000..5c7732a7 --- /dev/null +++ b/examples/log/fmt_tests/main.cpp @@ -0,0 +1,21 @@ +// include the fmt logger +#include + +#include +#include +#include + +// specialize the logging config variable template to use the fmt logger with a +// string destination +std::string log_buffer{}; + +template <> +inline auto logging::config<> = + logging::fmt::config{std::back_inserter(log_buffer)}; + +// logs will now use libfmt and go into the string where we can test the +// contents and clear the string in test setup code +auto main() -> int { + CIB_INFO("Hello"); + assert(log_buffer.find("Hello") != std::string::npos); +} diff --git a/examples/log/secure/CMakeLists.txt b/examples/log/secure/CMakeLists.txt new file mode 100644 index 00000000..c05e659a --- /dev/null +++ b/examples/log/secure/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) + +project(secure LANGUAGES CXX) + +if(NOT TARGET cib) + # to fetch cib, either use CPM (https://github.com/cpm-cmake/CPM.cmake) or + # use plain old CMake functionality + set(USE_CPM 1) + + set(CIB_VERSION "c388a4d") # update this to a more recent commit ID (or tag) + # for your project + + if(USE_CPM) + file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake + EXPECTED_HASH + SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a + ) + include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake) + + cpmaddpackage("gh:intel/compile-time-init-build#${CIB_VERSION}") + else() + include(FetchContent) + FetchContent_Declare( + cib + GIT_REPOSITORY https://github.com/intel/compile-time-init-build.git + GIT_TAG ${CIB_VERSION}) + FetchContent_MakeAvailable(cib) + endif() +endif() + +if(COMMAND add_example) + add_example(NAME secure FILES main.cpp LIBS cib_log_fmt) +else() + add_executable(secure main.cpp) + target_link_libraries(secure cib_log_fmt) +endif() diff --git a/examples/log/secure/main.cpp b/examples/log/secure/main.cpp new file mode 100644 index 00000000..21dc4f0f --- /dev/null +++ b/examples/log/secure/main.cpp @@ -0,0 +1,44 @@ +#include + +#include +#include +#include + +// declare a type to use for secure logs +struct secure_t; + +namespace { +auto get_file_output() { + static auto f = std::ofstream("log.txt"); + return std::ostream_iterator(f); +} +} // namespace + +// specialize the logging config variable template (with no args) to use the +// normal fmt logger +template <> +inline auto logging::config<> = + logging::fmt::config{std::ostream_iterator(std::cout)}; + +// specialize the logging config variable template (with the secure arg) to use +// the fmt logger to write to a file +template <> +inline auto logging::config = logging::fmt::config{get_file_output()}; + +// set up our own secure logging macros that use the secure path +#define SECURE_LOG_WITH_LEVEL(LEVEL, ...) \ + logging::log{}>>( \ + __FILE__, __LINE__, STDX_CT_FORMAT(__VA_ARGS__)) + +#define SECURE_INFO(...) \ + SECURE_LOG_WITH_LEVEL(logging::level::INFO __VA_OPT__(, ) __VA_ARGS__) + +auto main() -> int { + // ordinary logs go to std::cout + CIB_INFO("Hello"); + + // secure logs go to the file + SECURE_INFO("Secure hello"); +} diff --git a/examples/nexus/hello_world/CMakeLists.txt b/examples/nexus/hello_world/CMakeLists.txt index f5e0b4e0..c2e385a6 100644 --- a/examples/nexus/hello_world/CMakeLists.txt +++ b/examples/nexus/hello_world/CMakeLists.txt @@ -32,7 +32,14 @@ if(NOT TARGET cib) endif() if(COMMAND add_example) - add_example(NAME hello_world FILES main.cpp dont_panic.cpp) + add_example( + NAME + hello_world + FILES + main.cpp + dont_panic.cpp + LIBS + cib) else() add_executable(hello_world main.cpp dont_panic.cpp) target_link_libraries(hello_world cib) diff --git a/examples/nexus/serial_port/CMakeLists.txt b/examples/nexus/serial_port/CMakeLists.txt index e7a428e3..58454ae5 100644 --- a/examples/nexus/serial_port/CMakeLists.txt +++ b/examples/nexus/serial_port/CMakeLists.txt @@ -32,7 +32,7 @@ if(NOT TARGET cib) endif() if(COMMAND add_example) - add_example(NAME serial_port FILES main.cpp) + add_example(NAME serial_port FILES main.cpp LIBS cib) else() add_executable(serial_port main.cpp) target_link_libraries(serial_port cib)