refactor: separate log generation from log handling #34465

pull ryanofsky wants to merge 6 commits into bitcoin:master from ryanofsky:pr/mlog changing 37 files +239 −164
  1. ryanofsky commented at 5:59 pm on January 30, 2026: contributor

    This is a mostly move-only change. It’s a small refactoring that allows logging macros to be used by including a simple util/log.h header instead of the full logging.h logging implementation. Most of the changes here were cherry-picked from #34374.

    Original motivation for this change was to reduce the size and complexity of #34374 (kernel structured logging PR) and reduce the number of conflicts it causes with other PRs. But this should also make sense as a standalone change to have a clearer separation of concerns between log generation and log handling, and avoid needing to depend on the whole logging framework in call sites that only emit log messages.

    Recommended to review with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space

  2. DrahtBot added the label Refactoring on Jan 30, 2026
  3. DrahtBot commented at 6:00 pm on January 30, 2026: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK optout21, l0rinc, stickies-v, sedited

    If your review is incorrectly listed, please copy-paste <!–meta-tag:bot-skip–> into the comment that the bot should ignore.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #34514 (refactor: remove unnecessary std::move for trivially copyable types by l0rinc)
    • #34448 (ci, iwyu: Fix warnings in src/util and treat them as errors by hebasto)
    • #34436 (refactor + log: use new CeilDiv helper in UTXO Flushing warning by l0rinc)
    • #34435 (refactor: use _MiB/_GiB consistently for byte conversions by l0rinc)
    • #34176 (wallet: crash fix, handle non-writable db directories by furszy)
    • #34038 (logging: API improvements by ajtowns)
    • #33512 (coins: use number of dirty cache entries in flush warnings/logs by l0rinc)
    • #33324 (blocks: add -reobfuscate-blocks argument to enable (de)obfuscating existing blocks by l0rinc)
    • #31644 (leveldb: show non-default options during init by l0rinc)
    • #30342 (kernel, logging: Pass Logger instances to kernel objects by ryanofsky)
    • #29256 (log, refactor: Allow log macros to accept context arguments by ryanofsky)
    • #24230 (indexes: Stop using node internal types and locking cs_main, improve sync logic by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  4. in src/util/log.h:56 in f5b1dda3bd outdated
    51+                      .Write(s.line())
    52+                      .Write(MakeUCharSpan(std::string_view{s.file_name()}))
    53+                      .Finalize());
    54+    }
    55+};
    56+
    


    stickies-v commented at 6:31 pm on January 30, 2026:

    I intentionally left these two structs in logging.h because I think they’re ratelimiting implementations rather than source location attributes. They’re not part of the std::source_location interface, and e.g. it helps avoids pulling in the siphash dependency into util/log.h. I don’t think it’s unreasonable to move it, but just wanted to raise that.

    (nit note: in my latest branch, I also ended up moving this to util/source.h because it’s not really opinionated on logging and fits well with it being a std-wrapper, but i’m very okay with either approach).


    ryanofsky commented at 4:25 pm on February 2, 2026:

    re: #34465 (review)

    I intentionally left these two structs in logging.h because I think they’re ratelimiting implementations rather than source location attributes.

    Nice I didn’t notice that, Leaving them in logging.h makes the PR smaller and logging interface simpler, and could be good for compile times, too. It seems like these functions also make sense to keep in logging.h since they are only comparing and hashing selected fields, so are fairly application-specific.

  5. in src/logging.h:42 in 130df2ae9e outdated
    50-        Debug,     // Reasonably noisy logging, but still usable in production
    51-        Info,      // Default
    52-        Warning,
    53-        Error,
    54-    };
    55+    using Level = util::log::Level;
    


    l0rinc commented at 8:51 am on January 31, 2026:
    130df2ae9ecbef00bb094a016435c55ee78d5bd8 super-nit: this isn’t strictly a move, could be mentioned in the commit message - or just resolve the comment, just wanted to mention that I have checked it and looks fine

    ryanofsky commented at 2:08 pm on January 31, 2026:

    re: #34465 (review)

    130df2a super-nit: this isn’t strictly a move, could be mentioned in the commit message - or just resolve the comment, just wanted to mention that I have checked it and looks fine

    Thanks, updated commit message to mention type alias


    l0rinc commented at 10:02 pm on January 31, 2026:
    We don’t need this in the last commit anymore, since logging.h includes util/log.h, right?

    ryanofsky commented at 4:20 pm on February 2, 2026:

    re: #34465 (review)

    We don’t need this in the last commit anymore, since logging.h includes util/log.h, right?

    Yes good catch, there’s no reason to declare the same type both places.

  6. in src/util/log.h:81 in 616ba29fa2
    76+// evaluating arguments when logging for the category is not enabled.
    77+
    78+// Log by prefixing the output with the passed category name and severity level. This logs conditionally if
    79+// the category is allowed. No rate limiting is applied, because users specifying -debug are assumed to be
    80+// developers or power users who are aware that -debug may cause excessive disk usage due to logging.
    81+#define detail_LogIfCategoryAndLevelEnabled(category, level, ...)     \
    


    l0rinc commented at 8:52 am on January 31, 2026:
    616ba29fa2b824bbc3fe0233634e8d2e8b6216c0 nit: if we’ve reformatted enum LogFlags in the second commit, please consider it doing here as well, these things are awkward to maintain

    ryanofsky commented at 2:08 pm on January 31, 2026:

    re: #34465 (review)

    616ba29 nit: if we’ve reformatted enum LogFlags in the second commit, please consider it doing here as well, these things are awkward to maintain

    Makes sense, ran clang-format in this and other commits


    l0rinc commented at 2:42 pm on January 31, 2026:
    move-onlyish :p

    l0rinc commented at 2:48 pm on January 31, 2026:

    These lines didn’t change, what I mean was to decide if this is a good opportunity to untangle these lines:

    0#define detail_LogIfCategoryAndLevelEnabled(category, level, ...) \
    1    do { \
    2        if (LogAcceptCategory((category), (level))) { \
    3            bool rate_limit{level >= BCLog::Level::Info}; \
    4            Assume(!rate_limit); /*Only called with the levels below*/ \
    5            LogPrintLevel_(category, level, rate_limit, __VA_ARGS__); \
    6        } \
    7    } while (0)
    

    so that if I make one line longer or shorter we won’t have to update every line break anymore, like we forgot to do in e.g. https://github.com/bitcoin/bitcoin/blob/5ad94cf6b7eb2aefaebf04184ba2c187a304a8c4/src/test/script_tests.cpp#L1175-L1180 It seems clang-tidy doesn’t have an opinion on this.

    Edit: we aren’t always aligning the backslashes, e.g. https://github.com/bitcoin/bitcoin/blob/6eb5ba569141b722a5e27ef36e04994886769c44/src/crypto/siphash.cpp#L13-L20


    ryanofsky commented at 5:20 pm on February 2, 2026:

    re: #34465 (review)

    These lines didn’t change, what I mean was to decide if this is a good opportunity to untangle these lines:

    I think clang-format takes care of aligning backslashes, though not sure if you meant untangle in a different way. In general I am trying to avoid changes to the macros here to keep it targeted and simple to review, and because there are other PR’s changing the macros in more substantive ways

  7. in src/util/log.h:88 in 616ba29fa2 outdated
    59@@ -60,4 +60,35 @@ enum class Level {
    60 };
    61 } // namespace util::log
    62 
    63+// Allow __func__ to be used in any context without warnings:
    64+// NOLINTNEXTLINE(bugprone-lambda-function-name)
    


    l0rinc commented at 8:54 am on January 31, 2026:
    is this still needed? ./ci/lint.py passes for me locally without it

    ryanofsky commented at 2:12 pm on January 31, 2026:

    re: #34465 (review)

    is this still needed? ./ci/lint.py passes for me locally without it

    Yes, you can see the error by running clang-tidy on a file that uses log macros in lambdas:

    0cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
    1run-clang-tidy -quiet -p build src/rpc/server.cpp
    

    Errors look like src/rpc/server.cpp:298:9: error: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [bugprone-lambda-function-name,-warnings-as-errors]


    l0rinc commented at 2:43 pm on January 31, 2026:
    Ah, ran the wrong linter, thanks
  8. in src/logging.h:71 in 975ab0a605 outdated
    67-
    68-struct SourceLocationHasher {
    69-    size_t operator()(const SourceLocation& s) const noexcept
    70-    {
    71-        // Use CSipHasher(0, 0) as a simple way to get uniform distribution.
    72-        return size_t(CSipHasher(0, 0)
    


    l0rinc commented at 9:01 am on January 31, 2026:
    975ab0a60514943809f46c07e78125d80cd7a3e5 we shouldn’t need #include <crypto/siphash.h> here after the move

    ryanofsky commented at 2:12 pm on January 31, 2026:

    re: #34465 (review)

    975ab0a we shouldn’t need #include <crypto/siphash.h> here after the move

    Thanks, now removed in earlier commit

  9. in src/logging.h:152 in f5b1dda3bd
    148@@ -155,7 +149,7 @@ namespace BCLog {
    149         std::list<std::function<void(const std::string&)>> m_print_callbacks GUARDED_BY(m_cs) {};
    150 
    151         /** Send a string to the log output (internal) */
    152-        void LogPrintStr_(std::string_view str, SourceLocation&& source_loc, BCLog::LogFlags category, BCLog::Level level, bool should_ratelimit)
    153+        void LogPrintStr_(std::string_view str, SourceLocation&& source_loc, BCLog::LogFlags category, BCLog::Level level, bool should_ratelimit, std::optional<util::log::Time> time = std::nullopt)
    


    l0rinc commented at 9:05 am on January 31, 2026:
    The timestamp addition seems more than a refactor or a Move message formatting to util/log.h - can we do it in a separate commit?

    ryanofsky commented at 2:13 pm on January 31, 2026:

    re: #34465 (review)

    The timestamp addition seems more than a refactor or a Move message formatting to util/log.h - can we do it in a separate commit?

    Makes sense, updated to use a separate commit and expand the change slightly.

  10. in src/logging.h:371 in f5b1dda3bd outdated
    280@@ -287,18 +281,5 @@ static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level leve
    281 /** Return true if str parses as a log category and set the flag */
    282 bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str);
    283 
    284-template <typename... Args>
    285-inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    


    l0rinc commented at 9:08 am on January 31, 2026:
    What’s the reason for not moving LogPrintFormatInternal in a separate move-only commit? I can see that it comes with some baggage, but if it’s possible, it would make the last commit easier to review

    ryanofsky commented at 2:19 pm on January 31, 2026:

    re: #34465 (review)

    What’s the reason for not moving LogPrintFormatInternal in a separate move-only commit? I can see that it comes with some baggage, but if it’s possible, it would make the last commit easier to review

    It would be nice to move separately, but there isn’t a practical way to do it without including most of the the other changes in this commit. The problem is that LogPrintFormatInternal calls 2 Logger methods so it depends on the definition of the logger class. This commit just replaces those 2 message calls with function calls so this no longer depends on Logger. But hopefully this is still easy to review with suggested --color-moved options. It’s a 13 line function and 11 lines are moving unchanged.

  11. l0rinc commented at 9:08 am on January 31, 2026: contributor

    Concept ACK

    code review f5b1dda3bda6327eef270d28bf961624feaae44f

  12. ryanofsky force-pushed on Jan 31, 2026
  13. ryanofsky commented at 2:20 pm on January 31, 2026: contributor

    Thanks for the review!

    Updated f5b1dda3bda6327eef270d28bf961624feaae44f -> 9569400e51aa04dbbb99f4ee9162bdacafa0a818 (pr/mlog.1 -> pr/mlog.2, compare) with suggested changes

  14. in src/util/log.h:93 in 9569400e51
    88+} // namespace BCLog
    89+
    90+template <typename... Args>
    91+inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    92+{
    93+    if (util::log::ShouldLog(flag, level)) {
    


    l0rinc commented at 2:57 pm on January 31, 2026:

    9569400e51aa04dbbb99f4ee9162bdacafa0a818 This last commit is still more than a “Move”.

    The previous LogInstance().Enabled() https://github.com/bitcoin/bitcoin/blob/8bb77f348ef390b7f7c7fb6b57fdc7e86ddb4ce7/src/logging.h#L260-L265 was changed to util::log::ShouldLog(flag, level) https://github.com/bitcoin/bitcoin/blob/8bb77f348ef390b7f7c7fb6b57fdc7e86ddb4ce7/src/logging.cpp#L154-L158, which is always enabled for LogInfo (+ Warn & Error) so tfm::format below will always be executed. So calling https://github.com/bitcoin/bitcoin/blob/8bb77f348ef390b7f7c7fb6b57fdc7e86ddb4ce7/src/logging.cpp#L111-L121 would have gated it before, but not after.


    ryanofsky commented at 8:41 pm on January 31, 2026:

    re: #34465 (review)

    9569400 This last commit is still more than a “Move”.

    The previous LogInstance().Enabled()

    was changed to util::log::ShouldLog(flag, level)

    Nice catch. This code was just wrong. It didn’t effect much in practice because DisableLogging is only used by the kernel library and by a fuzz test, but this was a mistake.

  15. in src/util/log.h:1 in 9569400e51 outdated


    l0rinc commented at 3:09 pm on January 31, 2026:

    “With this change, callers can use util/log.h to log messages and do not need to include the full logging implementation in logging.h”

    What about debug logs that still need the LogAcceptCategory?

     0diff --git a/src/hash.h b/src/hash.h
     1--- a/src/hash.h	(revision c96e11340eaad06b5c10b36ff040574f8fef9867)
     2+++ b/src/hash.h	(date 1769872030470)
     3@@ -14,6 +14,7 @@
     4 #include <serialize.h>
     5 #include <span.h>
     6 #include <uint256.h>
     7+#include <util/log.h>
     8 
     9 #include <string>
    10 #include <vector>
    11@@ -28,6 +29,7 @@
    12     static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
    13 
    14     void Finalize(std::span<unsigned char> output) {
    15+        LogDebug(BCLog::NET, "hello\n");
    16         assert(output.size() == OUTPUT_SIZE);
    17         unsigned char buf[CSHA256::OUTPUT_SIZE];
    18         sha.Finalize(buf);
    

    fails with:

    /Users/lorinc/CLionProjects/bitcoin/src/hash.h:32:9: error: use of undeclared identifier ‘LogAcceptCategory’ 32 | LogDebug(BCLog::NET, “hello\n”);


    ryanofsky commented at 8:43 pm on January 31, 2026:

    re: #34465 (review)

    “With this change, callers can use util/log.h to log messages and do not need to include the full logging implementation in logging.h”

    Again nice catch. This is related to the mistake above. This commit should be replacing LogAcceptCategory() not Enabled() with ShouldLog()


    l0rinc commented at 9:45 pm on January 31, 2026:

    737999e5a8f3a0c7ebd0385b0f18c109fcd8c49d

    0-This change only effects tests which call DisableLogging so does not effect
    1-bitcoind A simpler alternative would be to stop evaluating format arguments
    2+This change only affects tests which call DisableLogging so does not affect
    3+bitcoind. A simpler alternative would be to stop evaluating format arguments
    

    ryanofsky commented at 4:18 pm on February 2, 2026:

    re: #34465 (review)

    Thank you, wound up rewriting this whole commit message to be clearer.


    stickies-v commented at 5:42 pm on February 2, 2026:
    I think your latest force-push undid the logging include change here, not sure that was intentional?

    ryanofsky commented at 5:48 pm on February 2, 2026:

    re: #34465 (review)

    I think your latest force-push undid the logging include change here, not sure that was intentional?

    Good catch. i have a combined branch with this and other logging changes and didn’t export from it correctly after rebasing. Should be fixed in new push


    optout21 commented at 10:06 am on February 5, 2026:
    Wouldn’t it be possible to expose LogInstance().Enabled() similar how ShouldLog() exposes LogInstance().WillLogCategoryLevel()? (for the issue mentioned in the commit msg)

    optout21 commented at 10:11 am on February 5, 2026:
    There is still a single #include <logging.h> within src/kernel (in bitcoinkernel.cpp), is that OK? (this comment is general, not specific for chainparams.cpp, but I wanted to keep with this change; sorry)

    stickies-v commented at 11:17 am on February 5, 2026:

    There is still a single #include <logging.h> within src/kernel (in bitcoinkernel.cpp), is that OK?

    bitcoinkernel.cpp uses LogInstance(), so yes, it is necessary to include its header here. In future work (https://github.com/bitcoin/bitcoin/pull/34374/changes/ebe4409b722facd7d019aa800e226e26db404f81), this will be removed.


    stickies-v commented at 11:24 am on February 5, 2026:

    Your comment seems to be on the entire util/log.h file so I’m not quite sure which line you’re referring to.

    ShouldLog() exposes LogInstance().WillLogCategoryLevel()

    It doesn’t, ShouldLog() is declared in util/log.h and has to be implemented by the application using it - which is done in logging.cpp. If util/log.h were to expose LogInstance(), we’d have to include logging.h which goes against the whole point of separation.


    ryanofsky commented at 2:08 pm on February 5, 2026:

    re: #34465 (review)

    Wouldn’t it be possible to expose LogInstance().Enabled() similar how ShouldLog() exposes LogInstance().WillLogCategoryLevel()? (for the issue mentioned in the commit msg)

    I think it would be possible to define a LoggerEnabled function alongside ShouldLog but this would be a confusing interface for a logging backend to implement. If the goal is to preserve current behavior I think it would be clearer to just have ShouldLog return a tri-state DO_LOG / DO_NOT_LOG / DO_NOT_LOG_BUT_EVALUATE_ARGS value giving the log macros all the information they need from a single function, instead of defining two similar functions.

    I also think the DO_NOT_LOG_BUT_EVALUATE_ARGS behavior is not ideal and would like to see it removed, but I understand why it’s there and think changing it is outside the scope of this PR.


    maflcko commented at 2:41 pm on February 6, 2026:

    in 0bd4375d77d5acbd5da7d57fb150a0a3ee3b13ba: I think the commit message is wrong: It is possible for bitcoind to disable logging via -noprinttoconsole -nodebuglogfile, no? However the commit message seems to imply that it is only possible to disable logging via DisableLogging()?

    I think it could make sense to clarify/fix this?


    optout21 commented at 2:47 pm on February 6, 2026:

    It doesn’t, ShouldLog() is declared in util/log.h and has to be implemented by the application using it @stickies-v , it looks like I wasn’t clear in explaining: I didn’t mean to use ShouldLog(), but a new method defined similarly (declared in util/log.h, implemented in logging.cpp). But @ryanofsky’s reply (above) gave a good answer, I think there is no need to expand on this further.


    maflcko commented at 2:49 pm on February 6, 2026:

    At least locally with the diff on master:

     0diff --git a/src/init.cpp b/src/init.cpp
     1index a44cdf807e..991e87bbda 100644
     2--- a/src/init.cpp
     3+++ b/src/init.cpp
     4@@ -1423,6 +1423,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
     5         // Detailed error printed inside StartLogging().
     6         return false;
     7     }
     8+    std::cout << LogInstance().Enabled() << std::endl;
     9 
    10     LogInfo("Using at most %i automatic connections (%i file descriptors available)", nMaxConnections, available_fds);
    11 
    

    I get:

    0$ ./bld-cmake/bin/bitcoin-qt -noprinttoconsole -nodebuglogfile -datadir=/tmp -regtest 
    10
    

    ryanofsky commented at 4:04 pm on February 6, 2026:

    re: #34465 (review)

    Nice find! I didn’t know this was possible. Updated the commit message


    sedited commented at 1:25 pm on February 7, 2026:
    Preserving existing behaviour seems like a goal here, so why not do the Enabled() check as part of ShouldLog?

    ryanofsky commented at 2:29 pm on February 7, 2026:

    re: #34465 (review)

    Preserving existing behaviour seems like a goal here, so why not do the Enabled() check as part of ShouldLog?

    No observable behavior is changing in this PR. The commit message is just pointing out that internally there is an extra tinyformat strprintf call that can happen when -noprinttoconsole -nodebuglogfile options are used. The result of the call is discarded and the call does not affect anything.

    It would be nice to add the Enabled() check to ShouldLog(), but the problem is doing that would change behavior by causing log arguments not to be evaluated when logging is disabled. I think this could actually be a good change, but it needs to be done safely and should not happen in a PR that is just moving code and doing a small refactoring.

    It would be possible to complicate this PR so it remains a refactoring and also avoids an extra strprintf. One way would be to have ShouldLog return a tristate DO_LOG / DO_NOT_LOG / DO_NOT_LOG_BUT_EVALUATE_ARGS value and rewrite all the macros. Another way suggested by stickies above would be to have ShouldLog include && logger.Enabled(), and rewrite the macros to evaluate the logging arguments regardless of ShouldLog if the log level is high enough. Since both approaches involved rewriting the macros and added unnecessary complexity I did not think they were worth pursuing when we already have other follow-up PRs open that can address the strprintf call.


    sedited commented at 3:10 pm on February 7, 2026:

    but the problem is doing that would change behavior by causing log arguments not to be evaluated when logging is disabled.

    Ah right, I missed that the call to LogPrintFormatInternal actually evaluates the arguments. Why not add an Enabled call to the log.h API and keep the call to it in LogPrintFormatInternal? Seems like a small change, and it can easily be refactored/get rid of again in the follow-ups.


    ryanofsky commented at 4:02 pm on February 7, 2026:

    re: #34465 (review)

    Why not add an Enabled call to the log.h API and keep the call to it in LogPrintFormatInternal? Seems like a small change, and it can easily be refactored/get rid of again in the follow-ups.

    Yes, this is an alternative to rewriting the log macros that optout21 suggested in this thread. I feel like this would be providing an incoherent log generation API. The log generation API needs a hook to log, and hook to know whether logging is needed. Adding a third hook to tell if log outputs are enabled seems exposing it to information it shouldn’t know, and having it deduce what actions to take based on a combination of ShouldLog/Enabled seems ugly compared to directly telling what to do.

    So I’d say it would not be good to add a third Enabled hook to the log generation API to avoid an unobservable strprintf call that will not happen in typical usage, but if reviewers think it would make this PR better I can add it. I’d prefer to keep the PR in it’s current form of being mostly move-only, with one small refactoring commit, providing simple and a coherent log generation API.

    I’d also note PR had 3 acks prior to the last push which just edited a commit message and wrapped long lines, so from my perspective it feels a little like we are bikeshedding over this strprintf, and if I didn’t go out of my way to mention it in the commit message we wouldn’t even be talking about it. But I’m happy to go in any direction reviewers would prefer here.


    sedited commented at 9:30 pm on February 7, 2026:
    Thanks and apologies for re-iterating this. Seems like all of this has been addressed already.

    ryanofsky commented at 7:32 pm on February 9, 2026:

    re: #34465 (review)

    Thanks and apologies for re-iterating this

    No problem, I’d much rather see doubts raised, than see PR’s get stuck or mistakes get made. Also, #29256 commit 8714e10178c13ad55ee991c9298f9d5be0c628f8 is now rebased and gets rid of the extra strprintf.

  16. in src/util/log.h:8 in 9569400e51 outdated
    5@@ -6,7 +6,11 @@
    6 #define BITCOIN_UTIL_LOG_H
    7 
    8 #include <crypto/siphash.h>
    


    l0rinc commented at 3:10 pm on January 31, 2026:

    9569400e51aa04dbbb99f4ee9162bdacafa0a818 We should probably add string and chrono here:

    0#include <chrono>
    1#include <crypto/siphash.h>
    2#include <logging/categories.h> // IWYU pragma: export
    3#include <span.h>
    4#include <string>
    5#include <tinyformat.h>
    6#include <util/check.h>
    7#include <util/threadnames.h>
    

    ryanofsky commented at 8:44 pm on January 31, 2026:

    re: #34465 (review)

    9569400 We should probably add string and chrono here:

    Good catch, added string, but wound up simplifying and dropping the time type.

  17. in src/util/log.h:75 in 9569400e51
    70+    Category category;
    71+    Level level;
    72+    std::chrono::system_clock::time_point timestamp{std::chrono::system_clock::now()};
    73+    bool should_ratelimit{false}; //!< Hint for consumers if this entry should be ratelimited
    74+    SourceLocation source_loc;
    75+    std::string thread_name{util::ThreadGetInternalName()};
    


    l0rinc commented at 3:13 pm on January 31, 2026:
    thread_name seems unused - I assume it was used in the parent change. Can we either add it when it will be used or document why it’s not?

    ryanofsky commented at 8:57 pm on January 31, 2026:

    re: #34465 (review)

    thread_name seems unused - I assume it was used in the parent change. Can we either add it when it will be used or document why it’s not?

    Good catch. I didn’t realize it was unused. Dropped it here and also dropped timestamp to make this simpler. It will make sense for followup PR’s to add these fields when they are actually needed.

  18. in src/util/log.h:71 in 9569400e51 outdated
    86+namespace BCLog {
    87+using Level = util::log::Level;
    88+} // namespace BCLog
    89+
    90+template <typename... Args>
    91+inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    


    l0rinc commented at 3:17 pm on January 31, 2026:
    nit: we might as well remove the redundant inline while we’re here

    ryanofsky commented at 8:48 pm on January 31, 2026:

    re: #34465 (review)

    nit: we might as well remove the redundant inline while we’re here

    Kept for now to keep diff output more readable, since this line is move-only. I also don’t mind the reminder that the function is inline, even though I wouldn’t add it myself.

  19. in src/util/log.h:52 in 9569400e51 outdated
    68+
    69+struct Entry {
    70+    Category category;
    71+    Level level;
    72+    std::chrono::system_clock::time_point timestamp{std::chrono::system_clock::now()};
    73+    bool should_ratelimit{false}; //!< Hint for consumers if this entry should be ratelimited
    


    l0rinc commented at 3:17 pm on January 31, 2026:
    does this comment really help?

    ryanofsky commented at 8:50 pm on January 31, 2026:

    re: #34465 (review)

    does this comment really help?

    I’m not the author of this comment, but I would think it’s probably helpful to know that this value is only a hint and setting it may not force rate limiting or prevent it. Maybe the field could have a better name or the comment could be clarified, but the name seems to match existing code and the comment seems like it adds more information.


    l0rinc commented at 9:36 pm on January 31, 2026:

    only a hint and setting it may not force rate limiting

    Oh, that’s not what I understood from it…


    ryanofsky commented at 5:36 pm on February 2, 2026:

    re: #34465 (review)

    Oh, that’s not what I understood from it…

    I guess I don’t know much about the rate limiting implementation, but appreciate the comment indicating the field shouldn’t be strongly relied upon. I’m sure there could be a better description of how it’s intended to be used though.

  20. l0rinc changes_requested
  21. l0rinc commented at 3:20 pm on January 31, 2026: contributor
    Thanks for the quick update, went over it in more detail. The moves are all correct, I only have a few concerns about the last commit.
  22. ryanofsky force-pushed on Jan 31, 2026
  23. ryanofsky commented at 9:08 pm on January 31, 2026: contributor

    Appreciate the thorough review. I definitely rushed the last commit and missed some things. Addressed your comments below and made some simplifications.

    Updated 9569400e51aa04dbbb99f4ee9162bdacafa0a818 -> 737999e5a8f3a0c7ebd0385b0f18c109fcd8c49d (pr/mlog.2 -> pr/mlog.3, compare) fixing unintended change in behavior in last commit when DisableLogging() is used, cleaning up leftover LogAcceptCategory call, and dropping timestamp / thread name references the logging header that would make more sense in the followup PR.

  24. l0rinc approved
  25. l0rinc commented at 10:08 pm on January 31, 2026: contributor
    This seems mostly correct to me now, please see my remaining comments.
  26. in src/util/log.h:67 in 737999e5a8 outdated
    80+/** Send message to be logged. Applications using the logging library need to provide this. */
    81+void Log(Entry entry);
    82+} // namespace util::log
    83+
    84+namespace BCLog {
    85+using Level = util::log::Level;
    


    stickies-v commented at 1:26 pm on February 2, 2026:

    This is now defined here and in logging.h. Would remove this alias and just use util::log::Level in this file?

     0diff --git a/src/util/log.h b/src/util/log.h
     1index 2e26b3eeec..c64bda82d1 100644
     2--- a/src/util/log.h
     3+++ b/src/util/log.h
     4@@ -81,12 +81,8 @@ bool ShouldLog(Category category, Level level);
     5 void Log(Entry entry);
     6 } // namespace util::log
     7 
     8-namespace BCLog {
     9-using Level = util::log::Level;
    10-} // namespace BCLog
    11-
    12 template <typename... Args>
    13-inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    14+inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    15 {
    16     std::string log_msg;
    17     try {
    18@@ -105,9 +101,9 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
    19 // Be conservative when using functions that unconditionally log to debug.log!
    20 // It should not be the case that an inbound peer can fill up a user's storage
    21 // with debug.log entries.
    22-#define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__)
    23-#define LogWarning(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Warning, /*should_ratelimit=*/true, __VA_ARGS__)
    24-#define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__)
    25+#define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, util::log::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__)
    26+#define LogWarning(...) LogPrintLevel_(BCLog::LogFlags::ALL, util::log::Level::Warning, /*should_ratelimit=*/true, __VA_ARGS__)
    27+#define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, util::log::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__)
    28 
    29 // Use a macro instead of a function for conditional logging to prevent
    30 // evaluating arguments when logging for the category is not enabled.
    31@@ -118,14 +114,14 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
    32 #define detail_LogIfCategoryAndLevelEnabled(category, level, ...)      \
    33     do {                                                               \
    34         if (util::log::ShouldLog((category), (level))) {               \
    35-            bool rate_limit{level >= BCLog::Level::Info};              \
    36+            bool rate_limit{level >= util::log::Level::Info};              \
    37             Assume(!rate_limit); /*Only called with the levels below*/ \
    38             LogPrintLevel_(category, level, rate_limit, __VA_ARGS__);  \
    39         }                                                              \
    40     } while (0)
    41 
    42 // Log conditionally, prefixing the output with the passed category name.
    43-#define LogDebug(category, ...) detail_LogIfCategoryAndLevelEnabled(category, BCLog::Level::Debug, __VA_ARGS__)
    44-#define LogTrace(category, ...) detail_LogIfCategoryAndLevelEnabled(category, BCLog::Level::Trace, __VA_ARGS__)
    45+#define LogDebug(category, ...) detail_LogIfCategoryAndLevelEnabled(category, util::log::Level::Debug, __VA_ARGS__)
    46+#define LogTrace(category, ...) detail_LogIfCategoryAndLevelEnabled(category, util::log::Level::Trace, __VA_ARGS__)
    47 
    48 #endif // BITCOIN_UTIL_LOG_H
    

    l0rinc commented at 2:41 pm on February 2, 2026:
    Related to #34465 (review)

    ryanofsky commented at 4:38 pm on February 2, 2026:

    re: #34465 (review)

    Thanks, I deduplicated the alias but left the macros alone to avoid burden of maintaining unnecessary changes to them and requiring reviewers to review them. I have PR entirely rewriting the macros in #29256 and think as a group logging changes should be easier to understand if they are targeted and avoid expanding and changing the same lines of code repeatedly.

  27. in src/util/log.h:71 in 737999e5a8 outdated
    84+namespace BCLog {
    85+using Level = util::log::Level;
    86+} // namespace BCLog
    87+
    88+template <typename... Args>
    89+inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    


    stickies-v commented at 1:27 pm on February 2, 2026:
    nit: this file has quite a few lines exceeding 100 characters

    stickies-v commented at 1:53 pm on February 2, 2026:
    0inline void LogPrintFormatInternal(SourceLocation&& source_loc, util::log::Category flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    

    ryanofsky commented at 4:42 pm on February 2, 2026:

    re: #34465 (review)

    nit: this file has quite a few lines exceeding 100 characters

    That’s true and l0rinc also pointed out static is redundant. But this line is unchanged and I would probably prefer to keep it move-only if there isn’t a stronger reason to change it.


    ryanofsky commented at 4:44 pm on February 2, 2026:

    re: #34465 (review)

    Similar to last comments would like to avoid tweaking a line that’s just move-only and conflicts with #29256


    stickies-v commented at 10:00 am on February 3, 2026:

    nit: a couple of non-moveonly lines that would benefit from being shorter, if you have to retouch:

     0diff --git a/src/util/log.h b/src/util/log.h
     1index c895b204e0..aae23f0df1 100644
     2--- a/src/util/log.h
     3+++ b/src/util/log.h
     4@@ -54,7 +54,8 @@ struct Entry {
     5     std::string message;
     6 };
     7 
     8-/** Return whether messages with specified category and level should be logged. Applications using the logging library need to provide this. */
     9+/** Return whether messages with specified category and level should be logged. Applications using
    10+ * the logging library need to provide this. */
    11 bool ShouldLog(Category category, Level level);
    12 
    13 /** Send message to be logged. Applications using the logging library need to provide this. */
    14@@ -75,7 +76,12 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
    15     } catch (tinyformat::format_error& fmterr) {
    16         log_msg = "Error \"" + std::string{fmterr.what()} + "\" while formatting log message: " + fmt.fmt;
    17     }
    18-    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)});
    19+    util::log::Log(util::log::Entry{
    20+        .category = flag,
    21+        .level = level,
    22+        .should_ratelimit = should_ratelimit,
    23+        .source_loc = std::move(source_loc),
    24+        .message = std::move(log_msg)});
    25 }
    26 
    27 // Allow __func__ to be used in any context without warnings:
    

    ryanofsky commented at 3:26 pm on February 3, 2026:

    re: #34465 (review)

    nit: a couple of non-moveonly lines that would benefit from being shorter, if you have to retouch:

    Seems reasonable and I applied the change locally, so it will get included if there is another update


    ryanofsky commented at 4:05 pm on February 6, 2026:

    re: #34465 (review)

    nit: a couple of non-moveonly lines that would benefit from being shorter, if you have to retouch:

    Applied suggested diff in latest update

  28. in src/logging.cpp:616 in 737999e5a8 outdated
    611+void util::log::Log(util::log::Entry entry)
    612+{
    613+    BCLog::Logger& logger{LogInstance()};
    614+    if (logger.Enabled()) {
    615+        logger.LogPrintStr(std::move(entry.message), std::move(entry.source_loc), static_cast<BCLog::LogFlags>(entry.category), entry.level, entry.should_ratelimit);
    616+    }
    


    stickies-v commented at 2:20 pm on February 2, 2026:

    I think it would be better if ShouldLog does all filtering, and Log does unconditional logging. (Hastily) adapting my approach to this PR, we could end up with something like:

     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.


    ryanofsky commented at 4:52 pm on February 2, 2026:

    re: #34465 (review)

    I think it would be better if ShouldLog does all filtering, and Log does unconditional logging.

    Yes rewrote the commit message to be clearer about why it isn’t taking this approach. I do think the approach makes sense, and it was actually the first thing I tried to fix the previous broken push. But I think that change would need to be done in a standalone PR since it would be an externally observable change in behavior that could potentially affect non-logging code, or potentially be controversial. I don’t think it should be bundled into what is otherwise a mostly-moveonly refactoring PR.


    stickies-v commented at 5:21 pm on February 2, 2026:

    But I think that change would need to be done in a standalone PR

    Fair enough, I agree with your approach to keep this PR uncontroversial and easy to review and merge.


    stickies-v commented at 10:37 am on February 3, 2026:

    But I think that change would need to be done in a standalone PR since it would be an externally observable change in behavior that could potentially affect non-logging code, or potentially be controversial.

    I want to clarify - my earlier suggestion should not introduce any observable behaviour change with master. Argument evaluation is unchanged:

    • Info and higher: unconditionally evaluated
    • Debug and lower: evaluated iff WillLogCategoryLevel returns true

    The main change my diff introduces is that:

    • string formatting is skipped when !LogInstance().Enabled(), but afaict this cannot introduce behaviour in program flow
    • a new (early return true, trivially cheap) call to WillLogCategoryLevel() is made for Info and up

    I think it is reasonable to want to minimize code diffs/keep this move-only as much as possible, but I think it is inaccurate that my diff would increase observable behaviour change. 0bd4375d77d5acbd5da7d57fb150a0a3ee3b13ba introduces performance overhead (as you document in the commit message), whereas with my diff there would be more code change but no behaviour change and no performance overhead.

    I personally would prefer including this change in this PR, but am happy either way - it is not crucial and I agree keeping this easy to review is important. I find my diff easier to understand, but that is personal preference.


    ryanofsky commented at 3:51 pm on February 3, 2026:

    re: #34465 (review)

    I want to clarify - my earlier suggestion should not introduce any observable behaviour change with master. Argument evaluation is unchanged:

    You’re right. I just saw the && logger.Enabled() part of the suggestion and remembered I tried that already and it wasn’t equivalent. But the suggestion is also hardcoding (level) >= util::log::Level::Info in the macro to preserve current behavior.

    So the suggestion would be a correct alternative to the current implementation, but I’d still resist applying it because it is rewriting the logging macros when this PR is just trying to move them. I think the macros do need to rewritten, but it would be better to do in an intentional way where their real limitations are addressed (hardcoding behavior instead of delgating to the logger, relying on global state and not supporting source logging) and they can be reviewed once in a PR with clear a goal instead changing multiple times


    stickies-v commented at 10:04 pm on February 3, 2026:
    Alright, sounds good. Thanks for looking into it.
  29. stickies-v commented at 2:31 pm on February 2, 2026: contributor

    Approach ACK 737999e5a8f3a0c7ebd0385b0f18c109fcd8c49d

    I think it makes sense to cherry-pick d425d8dd0342e1879f5d6ad20cb01a3f43232150 here. It reduces unnecessary includes and probably helps avoid future merge conflicts, and can be cherry-picked with minimal changes.

  30. ryanofsky force-pushed on Feb 2, 2026
  31. ryanofsky commented at 5:14 pm on February 2, 2026: contributor

    Thanks for the reviews!

    Updated 737999e5a8f3a0c7ebd0385b0f18c109fcd8c49d -> c497eb216150c9f258fb134d38449fda8e270e2e (pr/mlog.3 -> pr/mlog.4, compare) dropping unneeded SourceLocation moves as suggested, and cherry-picking change from #34465#pullrequestreview-3729796924 to update includes after the earlier changes. Also rewrote commit message 04c7dd5a1a4171bbfda078ff80a289f17f94d1ba to be clearer about how it is trying to not change behavior.

    Updated c497eb216150c9f258fb134d38449fda8e270e2e -> 698a05427ed3bdd8255840ce963d7c8d6e7c3e92 (pr/mlog.4 -> pr/mlog.5, compare) due to conflict with #34462

    Rebased 698a05427ed3bdd8255840ce963d7c8d6e7c3e92 -> 03c929e10a4b3db22cc2a90da4ed69191bd8b771 (pr/mlog.5 -> pr/mlog.6, compare) due to conflict with #33878

    Updated 03c929e10a4b3db22cc2a90da4ed69191bd8b771 -> 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5 (pr/mlog.6 -> pr/mlog.7, compare) to fix IWYU errors https://github.com/bitcoin/bitcoin/actions/runs/21601163622/job/62247641249?pr=34465

  32. move-only: Move SourceLocation to util/log.h
    Introduce util/log.h as a lightweight header for code that only needs to emit
    log messages. Move SourceLocation into this header so log-emitting code no
    longer needs to include logging.h and depend on the full log management API.
    
    This is a move-only change and the first change of several changes that
    separate log generation from log handling. It also applies clang-format
    suggestions to the moved code.
    
    Review with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    f5233f7e98
  33. move-only: move logging categories to logging/categories.h
    Logging categories are currently shared between node and kernel. This
    separation allows future commits to completely remove kernel's
    dependency on logging.h.
    
    Also applies clang-format suggestions to the moved code.
    
    Review with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    56d113cab0
  34. move-onlyish: Move logging levels to util/log.h
    This is not strictly move-only because BCLog::Level is now defined as a type
    alias for util::log::Level;
    
    Review with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    94c0adf4e8
  35. move-only: Move logging macros to util/log.h
    Move logging macros to util/log.h so the entire codebase can use the same
    macros.
    
    Review with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    001f0a428e
  36. logging: Move message formatting to util/log.h
    With this change, callers can use util/log.h to emit log messages and do not need to
    include the full logging implementation in logging.h.
    
    There's a potential performance impact with this change from an extra
    `strprintf` call in log statements where `Logger::WillLogCategoryLevel` returns
    true but `Logger::Enabled` returns false. This happens when bitcoind is run
    with `-noprinttoconsole -nodebuglogfile` options.
    
    For background, log macro arguments are supposed to be evaluated when
    `Logger::WillLogCategoryLevel` returns true, even if log output is not enabled.
    Changing this behavior would be reasonable but needs consideration in a
    separate PR since not evaluating arguments in log statements has the potential
    to change non-logging behavior.
    
    The extra `strprintf` call could have been avoided by expanding this change and
    making the `ShouldLog()` function return a tri-state DO_LOG / DO_NOT_LOG /
    DO_NOT_LOG_ONLY_EVALUATE_ARGS value instead of a bool, but this complexity did
    not seem warranted.
    
    Review with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    bb8e9e7c4c
  37. logging: use util/log.h where possible
    Preparation for a future commit where kernel's dependency
    on logging.cpp is removed completely.
    
    Replace usage of logging\.h with util/log\.h where it
    suffices, and fix wrong includes according to iwyu.
    37cc2a2d95
  38. ryanofsky force-pushed on Feb 2, 2026
  39. ryanofsky force-pushed on Feb 2, 2026
  40. ryanofsky force-pushed on Feb 2, 2026
  41. DrahtBot added the label CI failed on Feb 2, 2026
  42. DrahtBot commented at 6:22 pm on February 2, 2026: contributor

    🚧 At least one of the CI tasks failed. Task iwyu: https://github.com/bitcoin/bitcoin/actions/runs/21601163622/job/62247641249 LLM reason (✨ experimental): IWYU detected include issues and failed, causing the CI test script to exit non-zero.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  43. DrahtBot removed the label CI failed on Feb 2, 2026
  44. in src/dbwrapper.cpp:17 in 24a1cd6b83 outdated
    12+#include <leveldb/iterator.h>
    13+#include <leveldb/options.h>
    14+#include <leveldb/slice.h>
    15+#include <leveldb/status.h>
    16+#include <leveldb/write_batch.h>
    17 #include <logging.h>
    


    stickies-v commented at 10:10 am on February 3, 2026:

    In 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5:

    As per the commit goal of removing logging.cpp from kernel, this include should be removed, and LogAcceptCategory replaced with ShouldLog:

     0diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
     1index eb222078b5..95faa0870c 100644
     2--- a/src/dbwrapper.cpp
     3+++ b/src/dbwrapper.cpp
     4@@ -14,7 +14,6 @@
     5 #include <leveldb/slice.h>
     6 #include <leveldb/status.h>
     7 #include <leveldb/write_batch.h>
     8-#include <logging.h>
     9 #include <random.h>
    10 #include <serialize.h>
    11 #include <span.h>
    12@@ -58,7 +57,7 @@ public:
    13     // This code is adapted from posix_logger.h, which is why it is using vsprintf.
    14     // Please do not do this in normal code
    15     void Logv(const char * format, va_list ap) override {
    16-            if (!LogAcceptCategory(BCLog::LEVELDB, util::log::Level::Debug)) {
    17+            if (!util::log::ShouldLog(BCLog::LEVELDB, util::log::Level::Debug)) {
    18                 return;
    19             }
    20             char buffer[500];
    21@@ -277,7 +276,7 @@ CDBWrapper::~CDBWrapper()
    22 
    23 void CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
    24 {
    25-    const bool log_memory = LogAcceptCategory(BCLog::LEVELDB, util::log::Level::Debug);
    26+    const bool log_memory = util::log::ShouldLog(BCLog::LEVELDB, util::log::Level::Debug);
    27     double mem_before = 0;
    28     if (log_memory) {
    29         mem_before = DynamicMemoryUsage() / 1024.0 / 1024;
    

    ryanofsky commented at 3:48 pm on February 3, 2026:

    re: #34465 (review)

    As per the commit goal of removing logging.cpp from kernel, this include should be removed, and LogAcceptCategory replaced with ShouldLog

    I think the original goal of this commit and the goal of this PR might not line up exactly. This PR is just trying to in introduce the util/log.h header to expose a narrow log generation interface instead of the full log handling interface.

    I added this commit as a way of starting to include the header directly some places, but I’d resist expanding it to make extra changes to validation code. Specifically, I wouldn’t want the suggested ShouldLog replacement because I’m expecting the ShouldLog signature to change, either taking a context pointer following the g_dispatcher_should_log path from #34374 (comment), or taking a log source reference following #29256. Would like to try to keep this PR more focused and avoid churn where possible in cases like this.

  45. stickies-v approved
  46. stickies-v commented at 10:47 am on February 3, 2026: contributor

    ACK 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5

    This PR improves the status quo by reducing unnecessary dependencies on our logging sink, and makes it easier to work on several future improvements for kernel logging by minimizing merge conflicts / rebase overhead through carving out these mostly move-only changes.

    A few outstanding comments that I’d prefer being addressed before merging, but nothing blocking if they turn out more controversial than I expect.

  47. DrahtBot requested review from l0rinc on Feb 3, 2026
  48. in src/util/batchpriority.cpp:7 in 24a1cd6b83 outdated
    3@@ -4,7 +4,7 @@
    4 
    5 #include <util/batchpriority.h>
    6 
    7-#include <logging.h>
    8+#include <util/log.h>
    


    l0rinc commented at 1:14 pm on February 3, 2026:

    nit: if pthread.h and sched.h are already guarded (since they’re not always needed), shouldn’t we guard this with

    0#ifdef SCHED_BATCH
    1#include <util/log.h>
    2#endif
    

    so that it’s not unused otherwise?


    ryanofsky commented at 3:59 pm on February 3, 2026:

    re: #34465 (review)

    nit: if pthread.h and sched.h are already guarded (since they’re not always needed), shouldn’t we guard this with

    I think the reason pthread.h and sched.h are guarded isn’t because they aren’t always needed, but because they are posix headers that might not exist on all platforms. Guarding util/log.h the same way could be reasonable, but I could also imagine wanting to avoid conditional includes on our own headers since they could be a maintenance burden. But happy to make this change if there is another request for it.

  49. l0rinc approved
  50. l0rinc commented at 1:20 pm on February 3, 2026: contributor

    lightly tested code review ACK 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5

    Good refactor that cleanly reduces dependencies, and sets up kernel logging work without major behavior changes.

  51. ryanofsky commented at 4:23 pm on February 3, 2026: contributor
    Thanks for the reviews. I just responded below without making changes, since the PR seems to be in a good state now. I think all the concerns mentioned should be addressed either here currently or in the already open followup PRs.
  52. in src/util/log.h:1 in f5233f7e98 outdated
    0@@ -0,0 +1,32 @@
    1+// Copyright (c) The Bitcoin Core developers
    


    optout21 commented at 10:01 am on February 5, 2026:
    Nit: year(s) are not used in the copyright headers any more?

    l0rinc commented at 10:18 am on February 5, 2026:
    We’re going towards minimal edit churn, most years were removed in #34084 New code either omits it or only adds start time now.

    optout21 commented at 10:42 am on February 5, 2026:
    OK. Comment can be resolved. (I failed to resolve, sorry, maybe bc it’s a github review instance comment)
  53. in src/util/log.h:8 in 0bd4375d77 outdated
    4@@ -5,8 +5,13 @@
    5 #ifndef BITCOIN_UTIL_LOG_H
    6 #define BITCOIN_UTIL_LOG_H
    7 
    8+#include <logging/categories.h> // IWYU pragma: export
    


    optout21 commented at 10:05 am on February 5, 2026:
    Here util/log.h includes from logging. Wouldn’t it be better / more clear if categories.h would reside in util, so that those who use util/log.h only don’t need to see logging include folder?

    stickies-v commented at 11:15 am on February 5, 2026:

    util/log.h lets users “bring their own categories”.

    Currently, all categories used in are defined in BCLog::Categories which is a logging.h concern. This is why I opted for logging/categories.h instead of util/log/categories.h. Note: this is purely stylistic, the are no functional implications.

  54. optout21 commented at 10:16 am on February 5, 2026: contributor

    crACK 37cc2a2d953c072a236b657bfd7de5167092a47a Trivial diff

    Prev: crACK 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5

    This change is part of modularization/kernel-separation; a smaller part of high-impact separation process. It establishes the separation of logging internals from the logging interface, allowing for unified logging interface but different underlying implementation. It’s positive that the separation deals with code location and namespaces as well. The change is broken into smaller manageable commits. I’ve left some comments, mostly double-check questions / pointing attention to potential issues.

  55. maflcko commented at 2:41 pm on February 6, 2026: member

    24a1cd6b833df06da77eb0bcb0059a0999ce4fc5~1 🐬

    Signature:

    0untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
    1RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
    2trusted comment: 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5~1 🐬
    3+4GOCrP6hzVf4W6tdAWo4DdazjRFr1tb6C6GuZrYpMj9RLkDKPgfLeYhBXYEG+hCjltMSerhSunUZMixloeZDw==
    
  56. ryanofsky force-pushed on Feb 6, 2026
  57. ryanofsky commented at 4:07 pm on February 6, 2026: contributor

    Thanks for the reviews! Only changes since last review were wrapping some long lines as suggested and updating a commit message

    Updated 24a1cd6b833df06da77eb0bcb0059a0999ce4fc5 -> 37cc2a2d953c072a236b657bfd7de5167092a47a (pr/mlog.7 -> pr/mlog.8, compare)

  58. l0rinc commented at 4:55 pm on February 6, 2026: contributor

    diff ACK 37cc2a2d953c072a236b657bfd7de5167092a47a

    Since last ack a code section and comment were reformatted.

  59. DrahtBot requested review from stickies-v on Feb 6, 2026
  60. DrahtBot requested review from optout21 on Feb 6, 2026
  61. stickies-v commented at 4:58 pm on February 6, 2026: contributor

    re-ACK 37cc2a2d953c072a236b657bfd7de5167092a47a

    No changes except commit message update and wrapping long lines.

  62. sedited approved
  63. sedited commented at 9:31 pm on February 7, 2026: contributor
    ACK 37cc2a2d953c072a236b657bfd7de5167092a47a
  64. sedited merged this on Feb 7, 2026
  65. sedited closed this on Feb 7, 2026


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-02-11 00:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me