Skip to content

Commit e7bedfc

Browse files
committed
✨ Add fixed string IDs to logs
Problem: - Some hardware expects certain string IDs. When logging, it would be useful to be able to fix string IDs in code and have the tooling understand that. Solution: - Add the ability to specify string IDs in the logging environment.
1 parent 737aca4 commit e7bedfc

File tree

6 files changed

+67
-12
lines changed

6 files changed

+67
-12
lines changed

include/log/catalog/catalog.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace sc {
66
template <typename...> struct args;
7-
template <typename, typename T, T...> struct undefined;
7+
template <typename, auto, typename T, T...> struct undefined;
88

99
template <typename> struct message {};
1010
template <typename> struct module_string {};

include/log/catalog/encoder.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <log/catalog/catalog.hpp>
55
#include <log/log.hpp>
66
#include <log/module.hpp>
7+
#include <log/string_id.hpp>
78

89
#include <stdx/ct_string.hpp>
910
#include <stdx/span.hpp>
@@ -20,24 +21,26 @@
2021

2122
namespace logging::binary {
2223
namespace detail {
23-
template <typename S, typename... Args> constexpr static auto to_message() {
24+
template <typename S, auto Id, typename... Args>
25+
constexpr static auto to_message() {
2426
constexpr auto s = std::string_view{S::value};
2527
using char_t = typename std::remove_cv_t<decltype(s)>::value_type;
2628
return [&]<std::size_t... Is>(std::integer_sequence<std::size_t, Is...>) {
2729
return sc::message<
28-
sc::undefined<sc::args<Args...>, char_t, s[Is]...>>{};
30+
sc::undefined<sc::args<Args...>, Id, char_t, s[Is]...>>{};
2931
}(std::make_integer_sequence<std::size_t, std::size(s)>{});
3032
}
3133

3234
template <stdx::ct_string S> constexpr static auto to_module() {
3335
constexpr auto s = std::string_view{S};
3436
return [&]<std::size_t... Is>(std::integer_sequence<std::size_t, Is...>) {
35-
return sc::module_string<sc::undefined<void, char, s[Is]...>>{};
37+
return sc::module_string<sc::undefined<void, -1, char, s[Is]...>>{};
3638
}(std::make_integer_sequence<std::size_t, std::size(s)>{});
3739
}
3840

39-
template <typename S> struct to_message_t {
40-
template <typename... Args> using fn = decltype(to_message<S, Args...>());
41+
template <typename S, auto Id> struct to_message_t {
42+
template <typename... Args>
43+
using fn = decltype(to_message<S, Id, Args...>());
4144
};
4245
} // namespace detail
4346

@@ -85,7 +88,8 @@ template <typename Writer> struct log_handler {
8588
auto builder = get_builder(Env{});
8689
constexpr auto L = stdx::to_underlying(get_level(Env{}));
8790
using Message = typename decltype(builder)::template convert_args<
88-
detail::to_message_t<decltype(fr.str)>::template fn,
91+
detail::to_message_t<decltype(fr.str), logging::get_string_id(
92+
Env{})>::template fn,
8993
std::remove_cvref_t<Args>...>;
9094
using Module = decltype(detail::to_module<get_module(Env{})>());
9195
w(builder.template build<L>(catalog<Message>(), module<Module>(),

include/log/string_id.hpp

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

test/log/catalog1_lib.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ auto log_one_64bit_rt_arg() -> void;
3232
auto log_one_formatted_rt_arg() -> void;
3333
auto log_with_non_default_module_id() -> void;
3434
auto log_with_fixed_module_id() -> void;
35+
auto log_with_fixed_string_id() -> void;
3536

3637
auto log_zero_args() -> void {
3738
auto cfg = logging::binary::config{test_log_args_destination{}};
@@ -81,3 +82,12 @@ auto log_with_fixed_module_id() -> void {
8182
stdx::ct_format<"Fixed ModuleID string with {} placeholder">(1));
8283
}
8384
}
85+
86+
auto log_with_fixed_string_id() -> void {
87+
CIB_WITH_LOG_ENV(logging::get_level, logging::level::TRACE,
88+
logging::get_string_id, 1337) {
89+
auto cfg = logging::binary::config{test_log_args_destination{}};
90+
cfg.logger.log_msg<cib_log_env_t>(
91+
stdx::ct_format<"Fixed StringID string">());
92+
}
93+
}

test/log/catalog_app.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern auto log_two_rt_args() -> void;
1919
extern auto log_rt_enum_arg() -> void;
2020
extern auto log_with_non_default_module_id() -> void;
2121
extern auto log_with_fixed_module_id() -> void;
22+
extern auto log_with_fixed_string_id() -> void;
2223

2324
TEST_CASE("log zero arguments", "[catalog]") {
2425
test_critical_section::count = 0;
@@ -99,3 +100,13 @@ TEST_CASE("log with fixed module id", "[catalog]") {
99100
CHECK((last_header & expected_static) == expected_static);
100101
CHECK((last_header & ~expected_static) == (17u << 16u));
101102
}
103+
104+
TEST_CASE("log with fixed string id", "[catalog]") {
105+
test_critical_section::count = 0;
106+
log_calls = 0;
107+
log_with_fixed_string_id();
108+
CHECK(test_critical_section::count == 2);
109+
CHECK(log_calls == 1);
110+
// string ID 1337 is fixed by environment
111+
CHECK(last_header == ((1337u << 4u) | 1u));
112+
}

tools/gen_str_catalog.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,16 @@ def split_args(s: str) -> list[str]:
3232

3333

3434
string_re = re.compile(
35-
r"sc::message<sc::undefined<sc::args<(.*)>, char, (.*)>\s*>"
35+
r"sc::message<sc::undefined<sc::args<(.*)>, (.*), char, (.*)>\s*>"
3636
)
3737

3838

3939
def extract_string_id(line_m):
4040
catalog_type = line_m.group(1)
4141
string_m = string_re.match(line_m.group(3))
4242
arg_tuple = string_m.group(1)
43-
string_tuple = string_m.group(2).replace("(char)", "")
43+
string_id = int(string_m.group(2))
44+
string_tuple = string_m.group(3).replace("(char)", "")
4445
string_value = "".join((chr(int(c)) for c in re.split(r"\s*,\s*", string_tuple)))
4546
args = split_args(arg_tuple)
4647

@@ -51,11 +52,12 @@ def extract_string_id(line_m):
5152
type="flow" if string_value.startswith("flow.") else "msg",
5253
arg_types=args,
5354
arg_count=len(args),
55+
id=string_id
5456
),
5557
)
5658

5759

58-
module_re = re.compile(r"sc::module_string<sc::undefined<void, char, (.*)>\s?>")
60+
module_re = re.compile(r"sc::module_string<sc::undefined<void, -1, char, (.*)>\s?>")
5961

6062

6163
def module_string(module) -> str:
@@ -110,8 +112,18 @@ def get_id(stable_ids, key_fn, gen, obj):
110112
else:
111113
return next(gen)
112114

115+
unique_strings = {i[0][0]: i for i in strings}.values()
116+
113117
stable_msg_ids, stable_module_ids = stable_ids
114118

119+
for _, msg in filter(lambda u: u[1]["id"] != -1, unique_strings):
120+
stable_msg_ids[stable_msg_key(msg)] = msg["id"]
121+
122+
if len(stable_msg_ids) != len(set(stable_msg_ids.values())):
123+
import collections
124+
dupes = [item for item, count in collections.Counter(stable_msg_ids.values()).items() if count > 1]
125+
raise Exception(f"Duplicate string IDs found: {dupes}.")
126+
115127
old_msg_ids = set(stable_msg_ids.values())
116128
msg_id_gen = itertools.filterfalse(old_msg_ids.__contains__, itertools.count(0))
117129
get_msg_id = partial(get_id, stable_msg_ids, stable_msg_key, msg_id_gen)
@@ -122,7 +134,6 @@ def get_id(stable_ids, key_fn, gen, obj):
122134
)
123135
get_module_id = partial(get_id, stable_module_ids, stable_module_key, module_id_gen)
124136

125-
unique_strings = {i[0][0]: i for i in strings}.values()
126137
return (
127138
{m: {"string": module_string(m), "id": get_module_id(m)} for m in sorted(set(modules))},
128139
{item[0]: {**item[1], "id": get_msg_id(item[1])} for item in unique_strings},
@@ -144,7 +155,7 @@ def make_cpp_module_defn(m: str, text: str, n: int) -> str:
144155
return f"""/*
145156
"{text}"
146157
*/
147-
template<> unsigned int module<sc::module_string<sc::undefined<void, char, {m}>>>() {{
158+
template<> unsigned int module<sc::module_string<sc::undefined<void, -1, char, {m}>>>() {{
148159
return {n};
149160
}}"""
150161

0 commit comments

Comments
 (0)