Skip to content

Commit 3e330ee

Browse files
committed
🎨 Move log flavor into logging environment
1 parent 5fd1bbd commit 3e330ee

File tree

9 files changed

+127
-44
lines changed

9 files changed

+127
-44
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ target_sources(
135135
include
136136
FILES
137137
include/log/env.hpp
138+
include/log/flavor.hpp
138139
include/log/level.hpp
139140
include/log/log.hpp
140141
include/log/module.hpp)

docs/logging.adoc

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,16 @@ implementation is a matter of defining this structure appropriately.
8686
----
8787
struct my_logger_config {
8888
struct {
89-
template <logging::level L, typename ModuleId,
90-
typename File, typename Line, typename Msg>
89+
template <typename Env, typename File, typename Line, typename Msg>
9190
auto log(File, Line, Msg const &msg) -> void {
9291
// log according to my mechanism
9392
}
9493
} logger;
9594
};
9695
----
9796

98-
Notice that the first two template parameters to log are the
99-
xref:logging.adoc#_log_levels[level] and the xref:logging.adoc#_modules[module
100-
ID]. The `ModuleId` type is a xref:sc.adoc#_string_constants[compile-time string].
97+
Notice that the first template parameters to log is the
98+
xref:logging.adoc#_logging_environments[environment].
10199

102100
The first two runtime parameters receive preprocessor `\_​_FILE_​\_` and `__LINE_​_` values
103101
respectively. The `msg` argument is a structure containing a
@@ -109,8 +107,7 @@ way to implement `log` is:
109107
----
110108
struct my_logger_config {
111109
struct {
112-
template <logging::level L, typename ModuleId,
113-
typename File, typename Line, typename Msg>
110+
template <typename Env, typename File, typename Line, typename Msg>
114111
auto log(File, Line, Msg const &msg) -> void {
115112
msg.apply([] <typename Str> (Str, auto const&... args) {
116113
std::print(Str::value, args...);
@@ -236,3 +233,47 @@ The easiest way to flavor the version logging is to define a macro in terms of
236233
----
237234
#define LOG_SECURE_VERSION(...) CIB_LOG_V(secure_tag)
238235
----
236+
237+
=== Logging environments
238+
239+
The logging environment is a compile-time map from types to values that allows a
240+
logger to look up various parameters, including the module ID, the log level,
241+
and the flavor. It can also be used to provide user-defined values to be
242+
interpreted by a logging backend.
243+
244+
The macros that implement logging with various levels, modules, and flavors
245+
are implemented as environment declarations, for example:
246+
[source,cpp]
247+
----
248+
CIB_LOG_ENV(logging::get_level, logging::level::TRACE);
249+
CIB_LOG("Hello"); // logs with TRACE level
250+
----
251+
or:
252+
[source,cpp]
253+
----
254+
CIB_LOG_ENV(logging::get_flavor, secure_tag);
255+
CIB_TRACE("Hello"); // logs with secure back end
256+
----
257+
A temporary override of values can be done with `CIB_WITH_LOG_ENV`:
258+
[source,cpp]
259+
----
260+
CIB_WITH LOG_ENV(logging::get_level, logging::level::TRACE,
261+
logging::get_flavor, secure_tag) {
262+
CIB_LOG("Hello"); // logs a TRACE with secure back end
263+
}
264+
----
265+
266+
To interrogate the environment from a custom logger, use the appropriate query
267+
on the environment.
268+
[source,cpp]
269+
----
270+
struct my_logger_config {
271+
struct {
272+
template <typename Env, typename File, typename Line, typename Msg>
273+
auto log(File, Line, Msg const &msg) -> void {
274+
constexpr auto level = get_level(Env{}).value;
275+
// ...
276+
}
277+
} logger;
278+
};
279+
----

include/flow/impl.hpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
#include <flow/common.hpp>
44
#include <flow/log.hpp>
55
#include <log/env.hpp>
6+
#include <log/flavor.hpp>
67
#include <log/level.hpp>
78
#include <log/log.hpp>
89

910
#include <stdx/ct_string.hpp>
1011
#include <stdx/span.hpp>
12+
#include <stdx/type_traits.hpp>
1113

1214
#include <algorithm>
1315
#include <array>
@@ -22,9 +24,11 @@ constexpr auto run_func() -> void {
2224
if constexpr (not FlowName.empty()) {
2325
using log_spec_t =
2426
decltype(get_log_spec<CTNode, log_spec_id_t<FlowName>>());
25-
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
26-
CIB_LOG(typename log_spec_t::flavor, "flow.{}({})",
27-
typename CTNode::type_t{}, typename CTNode::name_t{});
27+
CIB_LOG_ENV(logging::get_level, log_spec_t::level,
28+
logging::get_flavor,
29+
stdx::type_identity<typename log_spec_t::flavor>{});
30+
CIB_LOG("flow.{}({})", typename CTNode::type_t{},
31+
typename CTNode::name_t{});
2832
}
2933
typename CTNode::func_t{}();
3034
}
@@ -62,16 +66,20 @@ template <stdx::ct_string Name, auto... FuncPtrs> struct inlined_func_list {
6266

6367
if constexpr (loggingEnabled) {
6468
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
65-
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
66-
CIB_LOG(typename log_spec_t::flavor, "flow.start({})", name);
69+
CIB_LOG_ENV(logging::get_level, log_spec_t::level,
70+
logging::get_flavor,
71+
stdx::type_identity<typename log_spec_t::flavor>{});
72+
CIB_LOG("flow.start({})", name);
6773
}
6874

6975
(FuncPtrs(), ...);
7076

7177
if constexpr (loggingEnabled) {
7278
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
73-
CIB_LOG_ENV(logging::get_level, log_spec_t::level);
74-
CIB_LOG(typename log_spec_t::flavor, "flow.end({})", name);
79+
CIB_LOG_ENV(logging::get_level, log_spec_t::level,
80+
logging::get_flavor,
81+
stdx::type_identity<typename log_spec_t::flavor>{});
82+
CIB_LOG("flow.end({})", name);
7583
}
7684
}
7785
};

include/log/env.hpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,11 @@ constexpr auto make_env = []<detail::autowrap... Args> {
7777
return boost::mp11::mp_append<new_env_t, Env>{};
7878
};
7979

80+
template <typename Env, detail::autowrap... Args>
81+
using extend_env_t = decltype(make_env<Env>.template operator()<Args...>());
82+
8083
template <detail::autowrap... Args>
81-
using make_env_t = decltype(make_env<>.template operator()<Args...>());
84+
using make_env_t = extend_env_t<env<>, Args...>;
8285
} // namespace logging
8386

8487
using cib_log_env_t = logging::env<>;
@@ -92,13 +95,8 @@ using cib_log_env_t = logging::env<>;
9295
#endif
9396

9497
#define CIB_LOG_ENV_DECL(...) \
95-
[[maybe_unused]] typedef decltype([]<logging::detail:: \
96-
autowrap... _env_args> { \
97-
using new_env_t = \
98-
typename logging::detail::for_each_pair<std::make_index_sequence< \
99-
sizeof...(_env_args) / 2>>::template type<_env_args...>; \
100-
return boost::mp11::mp_append<new_env_t, cib_log_env_t>{}; \
101-
}.template operator()<__VA_ARGS__>()) cib_log_env_t
98+
[[maybe_unused]] typedef logging::extend_env_t<cib_log_env_t __VA_OPT__( \
99+
, ) __VA_ARGS__> cib_log_env_t
102100

103101
#define CIB_LOG_ENV(...) \
104102
STDX_PRAGMA(diagnostic push) \

include/log/flavor.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <stdx/compiler.hpp>
4+
#include <stdx/utility.hpp>
5+
6+
#include <utility>
7+
8+
namespace logging {
9+
struct default_flavor_t;
10+
11+
[[maybe_unused]] constexpr inline struct get_flavor_t {
12+
template <typename T>
13+
requires true
14+
CONSTEVAL auto operator()(T &&t) const noexcept(
15+
noexcept(std::forward<T>(t).query(std::declval<get_flavor_t>())))
16+
-> decltype(std::forward<T>(t).query(*this)) {
17+
return std::forward<T>(t).query(*this);
18+
}
19+
20+
CONSTEVAL auto operator()(auto &&) const {
21+
return stdx::ct<stdx::type_identity<default_flavor_t>{}>();
22+
}
23+
} get_flavor;
24+
} // namespace logging

include/log/level.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <log/env.hpp>
44

5+
#include <stdx/compiler.hpp>
56
#include <stdx/type_traits.hpp>
67

78
#include <array>

include/log/log.hpp

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <log/env.hpp>
4+
#include <log/flavor.hpp>
45
#include <log/level.hpp>
56
#include <log/module.hpp>
67
#include <sc/format.hpp>
@@ -9,6 +10,8 @@
910
#include <stdx/compiler.hpp>
1011
#include <stdx/ct_string.hpp>
1112
#include <stdx/panic.hpp>
13+
#include <stdx/type_traits.hpp>
14+
#include <stdx/utility.hpp>
1215

1316
#include <cstdint>
1417
#include <utility>
@@ -35,35 +38,33 @@ struct config {
3538

3639
template <typename...> inline auto config = null::config{};
3740

38-
struct default_flavor_t;
39-
40-
template <typename Flavor, typename... Ts>
41+
template <typename Env, typename... Ts>
4142
ALWAYS_INLINE constexpr static auto get_config() -> auto & {
42-
if constexpr (std::same_as<Flavor, default_flavor_t>) {
43+
using flavor_t = typename decltype(get_flavor(Env{}).value)::type;
44+
if constexpr (std::same_as<flavor_t, default_flavor_t>) {
4345
return config<Ts...>;
4446
} else {
45-
return config<Flavor, Ts...>;
47+
return config<flavor_t, Ts...>;
4648
}
4749
}
4850

49-
template <typename Flavor, typename Env, typename... Ts, typename... TArgs>
51+
template <typename Env, typename... Ts, typename... TArgs>
5052
ALWAYS_INLINE static auto log(TArgs &&...args) -> void {
51-
auto &cfg = get_config<Flavor, Ts...>();
53+
auto &cfg = get_config<Env, Ts...>();
5254
cfg.logger.template log<Env>(std::forward<TArgs>(args)...);
5355
}
5456
} // namespace logging
5557

5658
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
5759

58-
#define CIB_LOG(FLAVOR, MSG, ...) \
59-
logging::log<FLAVOR, cib_log_env_t>( \
60+
#define CIB_LOG(MSG, ...) \
61+
logging::log<cib_log_env_t>( \
6062
__FILE__, __LINE__, sc::format(MSG##_sc __VA_OPT__(, ) __VA_ARGS__))
6163

62-
#define CIB_LOG_WITH_LEVEL(LEVEL, ...) \
63-
do { \
64-
CIB_LOG_ENV(logging::get_level, LEVEL); \
65-
CIB_LOG(logging::default_flavor_t __VA_OPT__(, ) __VA_ARGS__); \
66-
} while (false)
64+
#define CIB_LOG_WITH_LEVEL(LEVEL, MSG, ...) \
65+
logging::log< \
66+
logging::extend_env_t<cib_log_env_t, logging::get_level, LEVEL>>( \
67+
__FILE__, __LINE__, sc::format(MSG##_sc __VA_OPT__(, ) __VA_ARGS__))
6768

6869
#define CIB_TRACE(...) \
6970
CIB_LOG_WITH_LEVEL(logging::level::TRACE __VA_OPT__(, ) __VA_ARGS__)
@@ -77,8 +78,7 @@ ALWAYS_INLINE static auto log(TArgs &&...args) -> void {
7778
#define CIB_FATAL(MSG, ...) \
7879
[](auto &&str) { \
7980
CIB_LOG_ENV(logging::get_level, logging::level::FATAL); \
80-
logging::log<logging::default_flavor_t, cib_log_env_t>(__FILE__, \
81-
__LINE__, str); \
81+
logging::log<cib_log_env_t>(__FILE__, __LINE__, str); \
8282
FWD(str).apply([]<typename S, typename... Args>(S s, Args... args) { \
8383
constexpr auto cts = stdx::ct_string_from_type(s); \
8484
stdx::panic<cts>(args...); \
@@ -89,9 +89,9 @@ ALWAYS_INLINE static auto log(TArgs &&...args) -> void {
8989
((expr) ? void(0) : CIB_FATAL("Assertion failure: " #expr))
9090

9191
namespace logging {
92-
template <typename Flavor, typename... Ts>
92+
template <typename Env, typename... Ts>
9393
ALWAYS_INLINE static auto log_version() -> void {
94-
auto &l_cfg = get_config<Flavor, Ts...>();
94+
auto &l_cfg = get_config<Env, Ts...>();
9595
auto &v_cfg = ::version::config<Ts...>;
9696
if constexpr (requires {
9797
l_cfg.logger.template log_build<v_cfg.build_id,
@@ -109,7 +109,9 @@ ALWAYS_INLINE static auto log_version() -> void {
109109
}
110110
} // namespace logging
111111

112-
#define CIB_LOG_V(FLAVOR) logging::log_version<FLAVOR>()
112+
#define CIB_LOG_V(FLAVOR) \
113+
logging::log_version<logging::extend_env_t< \
114+
cib_log_env_t, logging::get_flavor, stdx::type_identity<FLAVOR>{}>>()
113115
#define CIB_LOG_VERSION() CIB_LOG_V(logging::default_flavor_t)
114116

115117
// NOLINTEND(cppcoreguidelines-macro-usage)

test/log/fmt_logger.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <log/fmt/logger.hpp>
22

33
#include <stdx/ct_string.hpp>
4+
#include <stdx/type_traits.hpp>
45
#include <stdx/utility.hpp>
56

67
#include <catch2/catch_test_macros.hpp>
@@ -161,17 +162,24 @@ template <>
161162
inline auto logging::config<secure_t> =
162163
logging::fmt::config{std::back_inserter(secure_buffer)};
163164

165+
#define SECURE_TRACE(MSG, ...) \
166+
logging::log<logging::extend_env_t< \
167+
cib_log_env_t, logging::get_level, logging::level::TRACE, \
168+
logging::get_flavor, stdx::type_identity<secure_t>{}>>( \
169+
__FILE__, __LINE__, sc::format(MSG##_sc __VA_OPT__(, ) __VA_ARGS__))
170+
164171
TEST_CASE("logging can be flavored", "[fmt_logger]") {
165-
CIB_LOG_ENV(logging::get_level, logging::level::TRACE);
166172
buffer.clear();
167173
secure_buffer.clear();
168-
CIB_LOG(secure_t, "Hello");
174+
SECURE_TRACE("Hello");
169175
CAPTURE(secure_buffer);
170176
CHECK(secure_buffer.substr(secure_buffer.size() - std::size("Hello")) ==
171177
"Hello\n");
172178
CHECK(buffer.empty());
173179
}
174180

181+
#undef SECURE_TRACE
182+
175183
TEST_CASE("log version can be flavored", "[fmt_logger]") {
176184
buffer.clear();
177185
secure_buffer.clear();

test/log/level.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct fmt::formatter<std::integral_constant<custom_level, L>> {
3939
TEST_CASE("fmt logger works with custom level", "[level]") {
4040
CIB_LOG_ENV(logging::get_level, custom_level::THE_ONE_LEVEL);
4141
buffer.clear();
42-
CIB_LOG(logging::default_flavor_t, "Hello");
42+
CIB_LOG("Hello");
4343
CAPTURE(buffer);
4444
CHECK(buffer.find("THE_ONE_LEVEL [default]:") != std::string::npos);
4545
}

0 commit comments

Comments
 (0)