Skip to content

Commit

Permalink
Improve compile time string view logging levels
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Oct 23, 2023
1 parent a0d8b12 commit a565046
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 54 deletions.
30 changes: 21 additions & 9 deletions src/engine/include/coincenteroptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -34,6 +35,22 @@ struct CoincenterCmdLineOptions {
static constexpr int64_t kDefaultRepeatDurationSeconds =
std::chrono::duration_cast<TimeInS>(kDefaultRepeatTime).count();

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 @@ -221,18 +238,13 @@ struct CoincenterAllowedOptions {
static constexpr CommandLineOptionWithValue value[] = {
{{{"General", 100}, "help", 'h', "", "Display this information"}, &OptValueType::help},
{{{"General", 200}, "--data", "<path/to/data>", CoincenterCmdLineOptions::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)"},
{{{"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", "<levelName|0-6>", "Synonym of --log"}, &OptValueType::logConsole},
{{{"General", 400},
"--log-file",
"<levelName|0-6>",
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},
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 @@ -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)
}
}

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 @@ -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 };

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

#include <string_view>
#include <utility>

#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 {

Expand Down
48 changes: 17 additions & 31 deletions src/objects/src/logginginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<decltype(logLevelPos)>(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<kPrintLogNameSep, LoggingInfo::kLogLevelNames>::value);
}

} // namespace
Expand Down
73 changes: 64 additions & 9 deletions src/tech/include/static_string_view_helpers.hpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
#pragma once

#include <array>
#include <cstdint>
#include <string_view>

#include "mathhelpers.hpp"

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 @@ -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 <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 @@ -77,10 +132,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
9 changes: 6 additions & 3 deletions src/tech/src/gethostname.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
#include <Winsock2.h>
#include <winsock.h>
#else
#include <errno.h>
#include <unistd.h>

#include <cerrno>
#endif

namespace cct {
Expand All @@ -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) {
Expand Down
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

0 comments on commit a565046

Please sign in to comment.