From a565046f3afbfebb34f11caeee1dc780b9ee02dd Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Sun, 22 Oct 2023 23:37:37 +0200 Subject: [PATCH] Improve compile time string view logging levels --- src/engine/include/coincenteroptions.hpp | 30 +++++--- .../src/prometheusmetricgateway.cpp | 2 +- src/objects/include/logginginfo.hpp | 3 + src/objects/src/generalconfig.cpp | 9 +++ src/objects/src/logginginfo.cpp | 48 +++++------- .../include/static_string_view_helpers.hpp | 73 ++++++++++++++++--- src/tech/src/gethostname.cpp | 9 ++- .../test/static_string_view_helpers_test.cpp | 17 ++++- 8 files changed, 137 insertions(+), 54 deletions(-) diff --git a/src/engine/include/coincenteroptions.hpp b/src/engine/include/coincenteroptions.hpp index 384b5a89..c98f66b6 100644 --- a/src/engine/include/coincenteroptions.hpp +++ b/src/engine/include/coincenteroptions.hpp @@ -11,6 +11,7 @@ #include "exchangeinfomap.hpp" #include "exchangepublicapi.hpp" #include "loadconfiguration.hpp" +#include "logginginfo.hpp" #include "static_string_view_helpers.hpp" #include "staticcommandlineoptioncheck.hpp" #include "stringhelpers.hpp" @@ -34,6 +35,22 @@ struct CoincenterCmdLineOptions { static constexpr int64_t kDefaultRepeatDurationSeconds = std::chrono::duration_cast(kDefaultRepeatTime).count(); + static constexpr std::string_view kLogValue1 = ", CharToStringView_v<'>'>>; + + static constexpr std::string_view kLoggingLevelsSep = "|"; + static constexpr std::string_view kLoggingLevels = + make_joined_string_view::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, 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 = @@ -221,18 +238,13 @@ struct CoincenterAllowedOptions { static constexpr CommandLineOptionWithValue value[] = { {{{"General", 100}, "help", 'h', "", "Display this information"}, &OptValueType::help}, {{{"General", 200}, "--data", "", CoincenterCmdLineOptions::kData}, &OptValueType::dataDir}, - {{{"General", 300}, - "--log", - 'v', - "", - "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)"}, + {{{"General", 300}, "--log", 'v', CoincenterCmdLineOptions::kLogValue, CoincenterCmdLineOptions::kLog}, + &OptValueType::logConsole}, + {{{"General", 400}, "--log-console", CoincenterCmdLineOptions::kLogValue, "Synonym of --log"}, &OptValueType::logConsole}, - {{{"General", 400}, "--log-console", "", "Synonym of --log"}, &OptValueType::logConsole}, {{{"General", 400}, "--log-file", - "", + CoincenterCmdLineOptions::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}, diff --git a/src/monitoring/src/prometheusmetricgateway.cpp b/src/monitoring/src/prometheusmetricgateway.cpp index b95949ae..10674034 100644 --- a/src/monitoring/src/prometheusmetricgateway.cpp +++ b/src/monitoring/src/prometheusmetricgateway.cpp @@ -51,7 +51,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) } } diff --git a/src/objects/include/logginginfo.hpp b/src/objects/include/logginginfo.hpp index d4ba3b2f..068097de 100644 --- a/src/objects/include/logginginfo.hpp +++ b/src/objects/include/logginginfo.hpp @@ -19,6 +19,9 @@ class LoggingInfo { static constexpr int64_t kDefaultFileSizeInBytes = 5L * 1024 * 1024; static constexpr int32_t kDefaultNbMaxFiles = 10; static constexpr char const *const kOutputLoggerName = "output"; + 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 }; diff --git a/src/objects/src/generalconfig.cpp b/src/objects/src/generalconfig.cpp index 171b09e0..c08c3270 100644 --- a/src/objects/src/generalconfig.cpp +++ b/src/objects/src/generalconfig.cpp @@ -1,7 +1,16 @@ #include "generalconfig.hpp" +#include +#include + +#include "apioutputtype.hpp" +#include "cct_json.hpp" +#include "cct_log.hpp" #include "file.hpp" #include "generalconfigdefault.hpp" +#include "logginginfo.hpp" +#include "requestsconfig.hpp" +#include "timedef.hpp" namespace cct { diff --git a/src/objects/src/logginginfo.cpp b/src/objects/src/logginginfo.cpp index 47c106dd..21047f91 100644 --- a/src/objects/src/logginginfo.cpp +++ b/src/objects/src/logginginfo.cpp @@ -10,48 +10,34 @@ #include "cct_const.hpp" #include "cct_exception.hpp" #include "cct_fixedcapacityvector.hpp" -#include "timestring.hpp" -#ifndef CCT_MSVC #include "static_string_view_helpers.hpp" -#endif +#include "timestring.hpp" #include "unitsparser.hpp" namespace cct { namespace { -constexpr int8_t kMaxLogLevel = 6; - -int8_t LogPosFromLogStr(std::string_view logStr) { +auto LogPosFromLogStr(std::string_view logStr) { if (logStr.size() == 1) { - int8_t logLevelPos = logStr.front() - '0'; - if (logLevelPos < 0 || logLevelPos > kMaxLogLevel) { - throw exception("Unrecognized log level {}. Possible values are 0-{}", logStr, '0' + kMaxLogLevel); + const int8_t logLevelPos = logStr.front() - '0'; + if (logLevelPos < 0 || logLevelPos >= static_cast(LoggingInfo::kNbLogLevels)) { + throw exception("Unrecognized log level {}. Possible values are [0-{}]", logStr, + '0' + (LoggingInfo::kNbLogLevels - 1U)); } return logLevelPos; } - if (logStr == "off") { - return 0; - } - if (logStr == "critical") { - return 1; - } - if (logStr == "error") { - return 2; - } - if (logStr == "warning") { - return 3; - } - if (logStr == "info") { - return 4; - } - if (logStr == "debug") { - return 5; - } - if (logStr == "trace") { - return 6; + + int8_t logLevel = 0; + for (const auto logName : LoggingInfo::kLogLevelNames) { + if (logStr == logName) { + return logLevel; + } + ++logLevel; } - throw exception("Unrecognized log level name {}. Possible values are off|critical|error|warning|info|debug|trace", - logStr); + + static constexpr std::string_view kPrintLogNameSep = "|"; + throw exception("Unrecognized log level name {}. Possible values are {}", logStr, + make_joined_string_view::value); } } // namespace diff --git a/src/tech/include/static_string_view_helpers.hpp b/src/tech/include/static_string_view_helpers.hpp index c3f22079..20e10422 100644 --- a/src/tech/include/static_string_view_helpers.hpp +++ b/src/tech/include/static_string_view_helpers.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "mathhelpers.hpp" @@ -8,7 +9,7 @@ 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 @@ -16,15 +17,13 @@ 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 arr{}; + constexpr std::string_view::size_type len = (Strs.size() + ... + 0); + std::array 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 @@ -33,12 +32,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 static constexpr auto JoinStringView_v = JoinStringView::value; +/// Same as JoinStringView but with a char separator between each string_view +template +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(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 +static constexpr auto JoinStringViewWithSep_v = JoinStringViewWithSep::value; + +namespace details { +template +struct make_joined_string_view_impl; + +template +struct make_joined_string_view_impl> { + static constexpr auto value = JoinStringViewWithSep::value; +}; + +} // namespace details + +// make joined string view from array like value +template +using make_joined_string_view = details::make_joined_string_view_impl>; + /// Converts an integer value to its string_view representation at compile time. /// The underlying storage is not null terminated. template @@ -77,10 +132,10 @@ static constexpr auto IntToStringView_v = IntToStringView::value; template 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 diff --git a/src/tech/src/gethostname.cpp b/src/tech/src/gethostname.cpp index 87ad3606..3bcdddbe 100644 --- a/src/tech/src/gethostname.cpp +++ b/src/tech/src/gethostname.cpp @@ -7,8 +7,9 @@ #include #include #else -#include #include + +#include #endif namespace cct { @@ -25,10 +26,12 @@ HostNameGetter::HostNameGetter() { HostNameGetter::~HostNameGetter() { WSACleanup(); } #endif +// This method cannot be made static as it needs the RAII WSAStartup / WSACleanup wrapper in Windows. +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) string HostNameGetter::getHostName() const { string hostname(16U, '\0'); - static constexpr std::size_t kMaxHostNameSize = 1024; - std::size_t nullTerminatedCharPos = 0; + static constexpr string::size_type kMaxHostNameSize = 1024; + string::size_type nullTerminatedCharPos = 0; do { auto errorCode = ::gethostname(hostname.data(), hostname.size() - 1U); if (errorCode != 0) { diff --git a/src/tech/test/static_string_view_helpers_test.cpp b/src/tech/test/static_string_view_helpers_test.cpp index 778386d7..1d236fd3 100644 --- a/src/tech/test/static_string_view_helpers_test.cpp +++ b/src/tech/test/static_string_view_helpers_test.cpp @@ -3,7 +3,6 @@ #include namespace cct { -// JoinStringView namespace test1 { static_assert(JoinStringView_v<>.empty()); } // namespace test1 @@ -40,9 +39,25 @@ static constexpr std::string_view kStr4 = "in my bag"; static_assert(JoinStringView_v, 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 == + "apples|bananas|oranges|blueberries|strawberries"); + +static constexpr std::string_view kStrArr[] = {"apples", "bananas", "oranges", "blueberries", "strawberries"}; + +static_assert(make_joined_string_view::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 \ No newline at end of file