0diff --git a/src/logging.cpp b/src/logging.cpp
1index df6946d661..357a656946 100644
2--- a/src/logging.cpp
3+++ b/src/logging.cpp
4@@ -605,13 +605,11 @@ bool BCLog::Logger::SetCategoryLogLevel(std::string_view category_str, std::stri
5
6 bool util::log::ShouldLog(Category category, Level level)
7 {
8- return LogInstance().WillLogCategoryLevel(static_cast<BCLog::LogFlags>(category), level);
9+ BCLog::Logger& logger{LogInstance()};
10+ return logger.WillLogCategoryLevel(static_cast<BCLog::LogFlags>(category), level) && logger.Enabled();
11 }
12
13 void util::log::Log(util::log::Entry entry)
14 {
15- BCLog::Logger& logger{LogInstance()};
16- if (logger.Enabled()) {
17- logger.LogPrintStr(std::move(entry.message), std::move(entry.source_loc), static_cast<BCLog::LogFlags>(entry.category), entry.level, entry.should_ratelimit);
18- }
19+ LogInstance().LogPrintStr(std::move(entry.message), std::move(entry.source_loc), static_cast<BCLog::LogFlags>(entry.category), entry.level, entry.should_ratelimit);
20 }
21diff --git a/src/util/log.h b/src/util/log.h
22index 2e26b3eeec..26f1e7cb94 100644
23--- a/src/util/log.h
24+++ b/src/util/log.h
25@@ -97,9 +97,18 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
26 util::log::Log(util::log::Entry{.category = flag, .level = level, .should_ratelimit = should_ratelimit, .source_loc = std::move(source_loc), .message = std::move(log_msg)});
27 }
28
29-// Allow __func__ to be used in any context without warnings:
30-// NOLINTNEXTLINE(bugprone-lambda-function-name)
31-#define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__)
32+// For Info levels and up, arguments are always evaluated. For Debug and lower,
33+// arguments are ONLY evaluated when the log is actually produced.
34+#define LogPrintLevel_(category, level, should_ratelimit, ...) \
35+ do { \
36+ if (util::log::ShouldLog(category, level)) { \
37+ /* NOLINTNEXTLINE(bugprone-lambda-function-name) */ \
38+ LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__); \
39+ } else if ((level) >= util::log::Level::Info) { \
40+ /* For Info levels and up, we guarantee that arguments are always evaluated. */ \
41+ [](auto&&...) {}(__VA_ARGS__); \
42+ } \
43+ } while (0)
44
45 // Log unconditionally. Uses basic rate limiting to mitigate disk filling attacks.
46 // Be conservative when using functions that unconditionally log to debug.log!
47@@ -109,23 +118,8 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
48 #define LogWarning(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Warning, /*should_ratelimit=*/true, __VA_ARGS__)
49 #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__)
50
51-// Use a macro instead of a function for conditional logging to prevent
52-// evaluating arguments when logging for the category is not enabled.
53-
54-// Log by prefixing the output with the passed category name and severity level. This logs conditionally if
55-// the category is allowed. No rate limiting is applied, because users specifying -debug are assumed to be
56-// developers or power users who are aware that -debug may cause excessive disk usage due to logging.
57-#define detail_LogIfCategoryAndLevelEnabled(category, level, ...) \
58- do { \
59- if (util::log::ShouldLog((category), (level))) { \
60- bool rate_limit{level >= BCLog::Level::Info}; \
61- Assume(!rate_limit); /*Only called with the levels below*/ \
62- LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \
63- } \
64- } while (0)
65-
66 // Log conditionally, prefixing the output with the passed category name.
67-#define LogDebug(category, ...) detail_LogIfCategoryAndLevelEnabled(category, BCLog::Level::Debug, __VA_ARGS__)
68-#define LogTrace(category, ...) detail_LogIfCategoryAndLevelEnabled(category, BCLog::Level::Trace, __VA_ARGS__)
69+#define LogDebug(category, ...) LogPrintLevel_(category, util::log::Level::Debug, /*should_ratelimit=*/false, __VA_ARGS__)
70+#define LogTrace(category, ...) LogPrintLevel_(category, util::log::Level::Trace, /*should_ratelimit=*/false, __VA_ARGS__)
71
72 #endif // BITCOIN_UTIL_LOG_H
This better enables users (e.g. places where we conditionally calculate memusage) to avoid expensive and unnecessary operations, and is imo a more consistent implementation of the interface. I think it also addresses the “This is a minor change in behavior for statements where Logger::WillLogCategoryLevel() returns true and Logger::Enabled() returns false…” paragraphs in the 737999e5a8f3a0c7ebd0385b0f18c109fcd8c49d commit message.