Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve compile time string view logging levels #463

Merged
merged 1 commit into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions src/engine/include/coincenteroptionsdef.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "exchangeconfigmap.hpp"
#include "exchangepublicapi.hpp"
#include "loadconfiguration.hpp"
#include "logginginfo.hpp"
#include "static_string_view_helpers.hpp"
#include "staticcommandlineoptioncheck.hpp"
#include "timedef.hpp"
Expand All @@ -29,6 +30,22 @@ class CoincenterCmdLineOptionsDefinitions {
std::chrono::duration_cast<seconds>(kDefaultRepeatTime).count();

protected:
static constexpr std::string_view kLogValue1 = "<levelName|0-";
static constexpr std::string_view kLogValue =
JoinStringView_v<kLogValue1, IntToStringView_v<LoggingInfo::kNbLogLevels - 1U>, CharToStringView_v<'>'>>;

static constexpr std::string_view kLoggingLevelsSep = "|";
static constexpr std::string_view kLoggingLevels =
make_joined_string_view<kLoggingLevelsSep, LoggingInfo::kLogLevelNames>::value;

static constexpr std::string_view kLog1 =
"Sets the log level in the console during all execution. "
"Possible values are: (";
static constexpr std::string_view kLog2 = ") or (0-";
static constexpr std::string_view kLog3 = ") (overrides .log.console in general config file)";
static constexpr std::string_view kLog =
JoinStringView_v<kLog1, kLoggingLevels, kLog2, IntToStringView_v<LoggingInfo::kNbLogLevels>, kLog3>;

static constexpr std::string_view kOutput1 = "Output format. One of (";
static constexpr std::string_view kOutput2 = ") (default configured in general config file)";
static constexpr std::string_view kOutput =
Expand Down Expand Up @@ -145,18 +162,11 @@ struct CoincenterAllowedOptions : private CoincenterCmdLineOptionsDefinitions {
static constexpr CommandLineOptionWithValue value[] = {
{{{"General", 100}, "help", 'h', "", "Display this information"}, &OptValueType::help},
{{{"General", 200}, "--data", "<path/to/data>", kData}, &OptValueType::dataDir},
{{{"General", 300},
"--log",
'v',
"<levelName|0-6>",
"Sets the log level in the console during all execution. "
"Possible values are: (off|critical|error|warning|info|debug|trace) or "
"(0-6) (overrides .log.console in general config file)"},
&OptValueType::logConsole},
{{{"General", 400}, "--log-console", "<levelName|0-6>", "Synonym of --log"}, &OptValueType::logConsole},
{{{"General", 300}, "--log", 'v', kLogValue, kLog}, &OptValueType::logConsole},
{{{"General", 400}, "--log-console", kLogValue, "Synonym of --log"}, &OptValueType::logConsole},
{{{"General", 400},
"--log-file",
"<levelName|0-6>",
kLogValue,
"Sets the log level in files during all execution (overrides .log.file in general config file). "
"Number of rotating files to keep and their size is configurable in the general config file"},
&OptValueType::logFile},
Expand Down
2 changes: 1 addition & 1 deletion src/monitoring/src/prometheusmetricgateway.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ PrometheusMetricGateway::~PrometheusMetricGateway() {
// We should not throw in a destructor - catch any exception and do nothing, not even a log (it could throw)
try {
flush();
} catch (const std::exception&) {
} catch (const std::exception&) { // NOLINT(bugprone-empty-catch)
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/objects/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ add_unit_test(
CCT_DISABLE_SPDLOG
)

add_unit_test(
parseloglevel_test
src/parseloglevel.cpp
test/parseloglevel_test.cpp
LIBRARIES
coincenter_tech
DEFINITIONS
CCT_DISABLE_SPDLOG
)

add_unit_test(
wallet_test
test/wallet_test.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/objects/include/logginginfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class LoggingInfo {
static constexpr char const *const kOutputLoggerName = "output";
static constexpr std::string_view kJsonFieldConsoleLevelName = "consoleLevel";
static constexpr std::string_view kJsonFieldFileLevelName = "fileLevel";
static constexpr std::string_view kLogLevelNames[] = {"off", "critical", "error", "warning",
"info", "debug", "trace"};
static constexpr auto kNbLogLevels = std::size(kLogLevelNames);

enum class WithLoggersCreation : int8_t { kNo, kYes };

Expand Down
35 changes: 35 additions & 0 deletions src/objects/src/parseloglevel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "parseloglevel.hpp"

#include <cstdint>
#include <string_view>
#include <type_traits>

#include "cct_exception.hpp"
#include "logginginfo.hpp"
#include "static_string_view_helpers.hpp"

namespace cct {
int8_t LogPosFromLogStr(std::string_view logStr) {
if (logStr.size() == 1) {
const int8_t logLevelPos = logStr.front() - '0';
if (logLevelPos < 0 ||
logLevelPos >= static_cast<std::remove_const_t<decltype(logLevelPos)>>(LoggingInfo::kNbLogLevels)) {
throw exception("Unrecognized log level {}. Possible values are [0-{}]", logStr,
'0' + (LoggingInfo::kNbLogLevels - 1U));
}
return logLevelPos;
}

int8_t logLevel = 0;
for (const auto logName : LoggingInfo::kLogLevelNames) {
if (logStr == logName) {
return logLevel;
}
++logLevel;
}

static constexpr std::string_view kPrintLogNameSep = "|";
throw exception("Unrecognized log level name {}. Possible values are {}", logStr,
make_joined_string_view<kPrintLogNameSep, LoggingInfo::kLogLevelNames>::value);
}
} // namespace cct
8 changes: 0 additions & 8 deletions src/tech/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,6 @@ add_unit_test(
test/mathhelpers_test.cpp
)

add_unit_test(
parseloglevel_test
src/parseloglevel.cpp
test/parseloglevel_test.cpp
DEFINITIONS
CCT_DISABLE_SPDLOG
)

add_unit_test(
simpletable_test
src/simpletable.cpp
Expand Down
72 changes: 63 additions & 9 deletions src/tech/include/static_string_view_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@
namespace cct {

/// Concatenates variadic template std::string_view arguments at compile time and defines a std::string_view pointing on
/// a static storage. The storage is guaranteed to be null terminated.
/// a static storage. The storage is guaranteed to be null terminated (but not itself included in the returned value)
/// Adapted from
/// https://stackoverflow.com/questions/38955940/how-to-concatenate-static-strings-at-compile-time/62823211#62823211
template <std::string_view const&... Strs>
class JoinStringView {
private:
// Join all strings into a single std::array of chars
static constexpr auto impl() noexcept {
constexpr std::size_t len = (Strs.size() + ... + 0);
std::array<char, len + 1> arr{};
constexpr std::string_view::size_type len = (Strs.size() + ... + 0);
std::array<char, len + 1U> arr; // +1 for null terminated char
if constexpr (len > 0) {
auto append = [i = 0, &arr](auto const& s) mutable {
for (auto c : s) arr[i++] = c;
};
auto append = [it = arr.begin()](auto const& s) mutable { it = std::copy(s.begin(), s.end(), it); };
(append(Strs), ...);
}
arr[len] = 0;
arr.back() = '\0';
return arr;
}
// Give the joined string static storage
Expand All @@ -35,12 +33,68 @@ class JoinStringView {
public:
// View as a std::string_view
static constexpr std::string_view value{arr.data(), arr.size() - 1};

// c_str version (null-terminated)
static constexpr const char* const c_str = arr.data();
};

// Helper to get the value out
template <std::string_view const&... Strs>
static constexpr auto JoinStringView_v = JoinStringView<Strs...>::value;

/// Same as JoinStringView but with a char separator between each string_view
template <std::string_view const& Sep, std::string_view const&... Strs>
class JoinStringViewWithSep {
private:
// Join all strings into a single std::array of chars
static constexpr auto impl() noexcept {
constexpr std::string_view::size_type len = (Strs.size() + ... + 0);
constexpr auto nbSv = sizeof...(Strs);
std::array<char, std::max(len + 1U + ((nbSv == 0U ? 0U : (nbSv - 1U)) * Sep.size()),
static_cast<std::string_view::size_type>(1))>
arr;
if constexpr (len > 0) {
auto append = [it = arr.begin(), &arr](auto const& s) mutable {
if (it != arr.begin()) {
it = std::copy(Sep.begin(), Sep.end(), it);
}
it = std::copy(s.begin(), s.end(), it);
};
(append(Strs), ...);
}
arr.back() = '\0';
return arr;
}
// Give the joined string static storage
static constexpr auto arr = impl();

public:
// View as a std::string_view
static constexpr std::string_view value{arr.data(), arr.size() - 1};

// c_str version (null-terminated)
static constexpr const char* const c_str = arr.data();
};

// Helper to get the value out
template <std::string_view const& Sep, std::string_view const&... Strs>
static constexpr auto JoinStringViewWithSep_v = JoinStringViewWithSep<Sep, Strs...>::value;

namespace details {
template <std::string_view const& Sep, const auto& a, typename>
struct make_joined_string_view_impl;

template <std::string_view const& Sep, const auto& a, std::size_t... i>
struct make_joined_string_view_impl<Sep, a, std::index_sequence<i...>> {
static constexpr auto value = JoinStringViewWithSep<Sep, a[i]...>::value;
};

} // namespace details

// make joined string view from array like value
template <std::string_view const& Sep, const auto& a>
using make_joined_string_view = details::make_joined_string_view_impl<Sep, a, std::make_index_sequence<std::size(a)>>;

/// Converts an integer value to its string_view representation at compile time.
/// The underlying storage is not null terminated.
template <int64_t intVal>
Expand Down Expand Up @@ -79,10 +133,10 @@ static constexpr auto IntToStringView_v = IntToStringView<intVal>::value;
template <char Char>
class CharToStringView {
private:
static constexpr char c = Char;
static constexpr char ch = Char;

public:
static constexpr std::string_view value{&c, 1};
static constexpr std::string_view value{&ch, 1};
};

template <char Char>
Expand Down
42 changes: 0 additions & 42 deletions src/tech/src/parseloglevel.cpp

This file was deleted.

17 changes: 16 additions & 1 deletion src/tech/test/static_string_view_helpers_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <string_view>

namespace cct {
// JoinStringView
namespace test1 {
static_assert(JoinStringView_v<>.empty());
} // namespace test1
Expand Down Expand Up @@ -40,9 +39,25 @@ static constexpr std::string_view kStr4 = "in my bag";
static_assert(JoinStringView_v<kStr1, IntToStringView_v<70>, kStr2, IntToStringView_v<1894>, kStr3, kStr4> ==
"I have 70 oranges and 1894 bananas in my bag");
} // namespace test5
namespace test6 {
static constexpr std::string_view kSep = "|";
static constexpr std::string_view kStr1 = "apples";
static constexpr std::string_view kStr2 = "bananas";
static constexpr std::string_view kStr3 = "oranges";
static constexpr std::string_view kStr4 = "blueberries";
static constexpr std::string_view kStr5 = "strawberries";

static_assert(JoinStringViewWithSep_v<kSep, kStr1, kStr2, kStr3, kStr4, kStr5> ==
"apples|bananas|oranges|blueberries|strawberries");

static constexpr std::string_view kStrArr[] = {"apples", "bananas", "oranges", "blueberries", "strawberries"};

static_assert(make_joined_string_view<kSep, kStrArr>::value == "apples|bananas|oranges|blueberries|strawberries");
} // namespace test6

// IntToStringView
static_assert(IntToStringView_v<0> == "0");
static_assert(IntToStringView_v<37> == "37");
static_assert(IntToStringView_v<-1273006> == "-1273006");

} // namespace cct