Skip to content
Closed
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
12 changes: 2 additions & 10 deletions include/spdlog/cfg/helpers-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ namespace spdlog {
namespace cfg {
namespace helpers {

// inplace convert to lowercase
inline std::string &to_lower_(std::string &str) {
std::transform(str.begin(), str.end(), str.begin(), [](char ch) {
return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
});
return str;
}

// inplace trim spaces
inline std::string &trim_(std::string &str) {
Expand Down Expand Up @@ -82,10 +75,9 @@ SPDLOG_INLINE void load_levels(const std::string &levels_spec) {

for (auto &name_level : key_vals) {
const auto &logger_name = name_level.first;
const auto &level_name = to_lower_(name_level.second);
const auto level = level::from_str(level_name);
const auto level = level::from_str(name_level.second);
// ignore unrecognized level names
if (level == level::off && level_name != "off") {
if (level == level::off && !strings_equal_ci(name_level.second, to_string_view(level::off))) {
continue;
}
if (logger_name.empty()) // no logger name indicates global level
Expand Down
1 change: 1 addition & 0 deletions include/spdlog/cfg/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace helpers {
// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
//
SPDLOG_API void load_levels(const std::string &levels_spec);

} // namespace helpers

} // namespace cfg
Expand Down
29 changes: 26 additions & 3 deletions include/spdlog/common-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@ SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOE
}

SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT {
auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name);
auto it = std::find_if(std::begin(level_string_views), std::end(level_string_views),
[name](string_view_t sv) { return strings_equal_ci(name, sv); } );

if (it != std::end(level_string_views))
return static_cast<level::level_enum>(std::distance(std::begin(level_string_views), it));

// check also for "warn" and "err" before giving up..
if (name == "warn") {
if (strings_equal_ci(name, "warn") && strings_equal_ci(to_string_view(level::warn), "warning")) {
return level::warn;
}
if (name == "err") {
else if (strings_equal_ci(name, "err") && strings_equal_ci(to_string_view(level::err), "error")) {
// if (name == "err") {
return level::err;
}
return level::off;
Expand Down Expand Up @@ -65,4 +68,24 @@ SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) {

SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); }

#if __cplusplus >= 201703L
constexpr
#endif
SPDLOG_API char to_lower(char ch) {
Copy link
Owner

@gabime gabime Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why SPDLOG_API. I would expect SPDLOG_INLINE

return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
}


SPDLOG_INLINE bool strings_equal_ci(string_view_t s1, string_view_t s2) {
if (s1.size() != s2.size()) {
return false;
}
for(size_t idx = 0; idx < s1.size(); idx++) {
if (to_lower(s1[idx]) != to_lower(s2[idx])) {
return false;
}
}
return true;
}

} // namespace spdlog
8 changes: 8 additions & 0 deletions include/spdlog/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ enum level_enum : int {

SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;

// Checks whether name is the same as one of the log level names and returns the respective enum.
// The comparison is case-insensitive.
SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;

} // namespace level
Expand All @@ -296,6 +299,11 @@ enum class pattern_time_type {
utc // log utc
};

//
// Returns true if two strings are equal, case-insensitive
//
SPDLOG_API bool strings_equal_ci(string_view_t s1, string_view_t s2);
Copy link
Owner

@gabime gabime Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why SPDLOG_API ? i would expect SPDLOG_INLINE

Copy link
Author

@neundorf neundorf Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change that, no problem.

But if I didn't mix things up, there is a second merge request for the same issue:
#3535

If you prefer the other one, I wouldn't put more work into my merge request.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure yet. The other merge seems bit leaner indeed


//
// Log exception
//
Expand Down
2 changes: 2 additions & 0 deletions tests/test_misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ TEST_CASE("to_short_c_str", "[convert_to_short_c_str]") {

TEST_CASE("to_level_enum", "[convert_to_level_enum]") {
REQUIRE(spdlog::level::from_str("trace") == spdlog::level::trace);
REQUIRE(spdlog::level::from_str("TrAcE") == spdlog::level::trace);
REQUIRE(spdlog::level::from_str("debug") == spdlog::level::debug);
REQUIRE(spdlog::level::from_str("info") == spdlog::level::info);
REQUIRE(spdlog::level::from_str("warning") == spdlog::level::warn);
REQUIRE(spdlog::level::from_str("warn") == spdlog::level::warn);
REQUIRE(spdlog::level::from_str("error") == spdlog::level::err);
REQUIRE(spdlog::level::from_str("err") == spdlog::level::err);
REQUIRE(spdlog::level::from_str("critical") == spdlog::level::critical);
REQUIRE(spdlog::level::from_str("off") == spdlog::level::off);
REQUIRE(spdlog::level::from_str("null") == spdlog::level::off);
Expand Down
Loading