Skip to content

Commit bcbb631

Browse files
committed
🎨 Customize flow log levels
1 parent 5f7a6ad commit bcbb631

File tree

8 files changed

+199
-18
lines changed

8 files changed

+199
-18
lines changed

include/flow/builder.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <flow/common.hpp>
55
#include <flow/graph_builder.hpp>
66
#include <flow/impl.hpp>
7+
#include <log/level.hpp>
78

89
#include <stdx/ct_string.hpp>
910

include/flow/graph_builder.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <flow/common.hpp>
44
#include <flow/detail/walk.hpp>
55
#include <flow/impl.hpp>
6+
#include <log/level.hpp>
67

78
#include <stdx/ct_string.hpp>
89
#include <stdx/cx_multimap.hpp>

include/flow/impl.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ template <stdx::ct_string Name, std::size_t NumSteps> class impl {
7878
namespace detail {
7979
template <stdx::ct_string Name, auto... FuncPtrs> struct inlined_func_list {
8080
constexpr static auto active = sizeof...(FuncPtrs) > 0;
81+
constexpr static auto ct_name = Name;
8182

8283
__attribute__((flatten, always_inline)) auto operator()() const -> void {
8384
constexpr static bool loggingEnabled = not Name.empty();
@@ -86,13 +87,17 @@ template <stdx::ct_string Name, auto... FuncPtrs> struct inlined_func_list {
8687
stdx::ct_string_to_type<Name, sc::string_constant>();
8788

8889
if constexpr (loggingEnabled) {
89-
CIB_TRACE("flow.start({})", name);
90+
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
91+
CIB_LOG(typename log_spec_t::flavor, log_spec_t::level,
92+
"flow.start({})", name);
9093
}
9194

9295
(FuncPtrs(), ...);
9396

9497
if constexpr (loggingEnabled) {
95-
CIB_TRACE("flow.end({})", name);
98+
using log_spec_t = decltype(get_log_spec<inlined_func_list>());
99+
CIB_LOG(typename log_spec_t::flavor, log_spec_t::level,
100+
"flow.end({})", name);
96101
}
97102
}
98103
};

include/flow/log.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
#include <log/log.hpp>
4+
5+
#include <type_traits>
6+
7+
namespace flow {
8+
struct default_log_spec {
9+
using flavor = logging::default_flavor_t;
10+
constexpr static auto level = logging::level::TRACE;
11+
};
12+
template <stdx::ct_string, typename...>
13+
constexpr auto log_spec = default_log_spec{};
14+
15+
template <typename T, typename... DummyArgs>
16+
requires(sizeof...(DummyArgs) == 0)
17+
constexpr static auto get_log_spec() {
18+
if constexpr (std::is_same_v<decltype(log_spec<T::ct_name, DummyArgs...>),
19+
default_log_spec const>) {
20+
return log_spec<"default", DummyArgs...>;
21+
} else {
22+
return log_spec<T::ct_name, DummyArgs...>;
23+
}
24+
}
25+
26+
template <typename T, typename... DummyArgs, typename... Args>
27+
auto log_with_spec(Args &&...args) {
28+
using log_spec_t = decltype(get_log_spec<T, DummyArgs...>());
29+
logging::log<typename log_spec_t::flavor, log_spec_t::level,
30+
cib_log_module_id_t>(std::forward<Args>(args)...);
31+
}
32+
} // namespace flow

include/flow/step.hpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
#include <cib/detail/runtime_conditional.hpp>
44
#include <cib/func_decl.hpp>
55
#include <flow/common.hpp>
6+
#include <flow/log.hpp>
67
#include <flow/subgraph_identity.hpp>
7-
#include <log/log.hpp>
88
#include <sc/string_constant.hpp>
99

1010
#include <stdx/compiler.hpp>
@@ -25,7 +25,7 @@ struct rt_node {
2525

2626
template <stdx::ct_string Type, stdx::ct_string Name,
2727
subgraph_identity Identity, typename Cond, typename F>
28-
struct ct_node : rt_node {
28+
struct ct_node {
2929
using is_subgraph = void;
3030
using type_t =
3131
decltype(stdx::ct_string_to_type<Type, sc::string_constant>());
@@ -39,19 +39,21 @@ struct ct_node : rt_node {
3939

4040
constexpr static auto condition = Cond{};
4141

42-
constexpr static auto run_func = [] {
43-
if (condition) {
44-
F{}();
45-
}
46-
};
47-
48-
constexpr static auto log_func = [] {
49-
if (condition) {
50-
CIB_TRACE("flow.{}({})", type_t{}, name_t{});
51-
}
52-
};
53-
54-
constexpr ct_node() : rt_node{+run_func, +log_func} {}
42+
constexpr operator rt_node() const {
43+
return rt_node{
44+
[] {
45+
if (condition) {
46+
F{}();
47+
}
48+
},
49+
[] {
50+
if (condition) {
51+
using log_spec_t = decltype(get_log_spec<ct_node>());
52+
CIB_LOG(typename log_spec_t::flavor, log_spec_t::level,
53+
"flow.{}({})", type_t{}, name_t{});
54+
}
55+
}};
56+
}
5557

5658
constexpr auto operator*() const {
5759
if constexpr (Identity == subgraph_identity::REFERENCE) {

test/flow/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ else()
1515
warnings
1616
cib)
1717

18-
add_tests(flow logging)
18+
add_tests(flow logging log_levels custom_log_levels)
1919
endif()
2020

2121
add_tests(graph graph_builder)

test/flow/custom_log_levels.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include <cib/cib.hpp>
2+
#include <flow/flow.hpp>
3+
4+
#include <catch2/catch_test_macros.hpp>
5+
6+
#include <string>
7+
#include <vector>
8+
9+
namespace {
10+
using namespace flow::literals;
11+
12+
template <auto... Cs> struct wrapper {
13+
struct inner {
14+
constexpr static auto config = cib::config(Cs...);
15+
};
16+
constexpr static auto n = cib::nexus<inner>{};
17+
18+
wrapper() { n.init(); }
19+
20+
template <typename S> static auto run() -> void { n.template service<S>(); }
21+
};
22+
23+
std::vector<logging::level> log_calls{};
24+
25+
template <typename S, auto... Cs>
26+
constexpr auto run_flow = []() -> void {
27+
log_calls.clear();
28+
wrapper<Cs...>::template run<S>();
29+
};
30+
31+
struct TestFlowA : public flow::service<"A"> {};
32+
struct TestFlowB : public flow::service<"B"> {};
33+
34+
constexpr auto msA = flow::milestone<"msA">();
35+
constexpr auto msB = flow::milestone<"msB">();
36+
37+
struct log_config {
38+
struct log_handler {
39+
template <logging::level Level, typename ModuleId,
40+
typename FilenameStringType, typename LineNumberType,
41+
typename MsgType>
42+
auto log(FilenameStringType, LineNumberType, MsgType const &) -> void {
43+
log_calls.push_back(Level);
44+
}
45+
};
46+
log_handler logger;
47+
};
48+
} // namespace
49+
50+
template <> inline auto logging::config<> = log_config{};
51+
52+
struct user1_log_spec : flow::default_log_spec {
53+
constexpr static auto level = logging::level::USER1;
54+
};
55+
struct user2_log_spec : flow::default_log_spec {
56+
constexpr static auto level = logging::level::USER2;
57+
};
58+
struct info_log_spec : flow::default_log_spec {
59+
constexpr static auto level = logging::level::INFO;
60+
};
61+
template <> constexpr auto flow::log_spec<"default"> = info_log_spec{};
62+
63+
TEST_CASE("override default log level", "[flow_custom_log_levels]") {
64+
run_flow<TestFlowA, cib::exports<TestFlowA>,
65+
cib::extend<TestFlowA>(*msA)>();
66+
67+
REQUIRE(not log_calls.empty());
68+
std::for_each(std::begin(log_calls), std::end(log_calls),
69+
[](auto level) { CHECK(level == logging::level::INFO); });
70+
}
71+
72+
template <> constexpr auto flow::log_spec<"B"> = user1_log_spec{};
73+
template <> constexpr auto flow::log_spec<"msB"> = user2_log_spec{};
74+
75+
TEST_CASE("override log level by name", "[flow_custom_log_levels]") {
76+
run_flow<TestFlowB, cib::exports<TestFlowB>,
77+
cib::extend<TestFlowB>(*msB)>();
78+
79+
REQUIRE(log_calls.size() == 3);
80+
CHECK(log_calls[0] == logging::level::USER1);
81+
CHECK(log_calls[1] == logging::level::USER2);
82+
CHECK(log_calls[2] == logging::level::USER1);
83+
}

test/flow/log_levels.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <cib/cib.hpp>
2+
#include <flow/flow.hpp>
3+
4+
#include <catch2/catch_test_macros.hpp>
5+
6+
#include <string>
7+
#include <vector>
8+
9+
namespace {
10+
using namespace flow::literals;
11+
12+
template <auto... Cs> struct wrapper {
13+
struct inner {
14+
constexpr static auto config = cib::config(Cs...);
15+
};
16+
constexpr static auto n = cib::nexus<inner>{};
17+
18+
wrapper() { n.init(); }
19+
20+
template <typename S> static auto run() -> void { n.template service<S>(); }
21+
};
22+
23+
std::vector<logging::level> log_calls{};
24+
25+
template <typename S, auto... Cs>
26+
constexpr auto run_flow = []() -> void {
27+
log_calls.clear();
28+
wrapper<Cs...>::template run<S>();
29+
};
30+
31+
struct NamedTestFlow : public flow::service<"TestFlow"> {};
32+
33+
constexpr auto ms = flow::milestone<"ms">();
34+
35+
struct log_config {
36+
struct log_handler {
37+
template <logging::level Level, typename ModuleId,
38+
typename FilenameStringType, typename LineNumberType,
39+
typename MsgType>
40+
auto log(FilenameStringType, LineNumberType, MsgType const &) -> void {
41+
log_calls.push_back(Level);
42+
}
43+
};
44+
log_handler logger;
45+
};
46+
} // namespace
47+
48+
template <> inline auto logging::config<> = log_config{};
49+
50+
TEST_CASE("flow logs at TRACE by default", "[flow_log_levels]") {
51+
run_flow<NamedTestFlow, cib::exports<NamedTestFlow>,
52+
cib::extend<NamedTestFlow>(*ms)>();
53+
54+
REQUIRE(not log_calls.empty());
55+
std::for_each(std::begin(log_calls), std::end(log_calls),
56+
[](auto level) { CHECK(level == logging::level::TRACE); });
57+
}

0 commit comments

Comments
 (0)