refactor: logging: Various API improvements #34806

pull ajtowns wants to merge 9 commits into bitcoin:master from ajtowns:202603-log-niceties2 changing 71 files +153 −122
  1. ajtowns commented at 4:45 PM on March 11, 2026: contributor

    ShrinkDebugFile now takes the logging mutex for its entire run; though it's only called in init so shouldn't have any races in the first place.

    Adds a NO_RATE_LIMIT tag that can be used with info/warning/error logs to avoid rate-limiting. This allows LogPrintLevel_ to be restricted to being an internal API.

    The GetLogCategory function is moved out of the global namespace.

    ShouldLog is split into separate ShouldDebugLog and ShouldTraceLog so that filtering checks are somewhat more enforced via function signature checks.

    Redundant LogAcceptCategory function is removed.

    More files are pointed at util/log.h instead of logging.h.

  2. DrahtBot added the label Refactoring on Mar 11, 2026
  3. DrahtBot commented at 4:46 PM on March 11, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34806.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK maflcko, sedited, l0rinc, ryanofsky

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35322 (logging: streamline Logger state and drop redundant methods by ryanofsky)
    • #35205 (kernel,node: clean up dbcache helpers and add kernel API by l0rinc)
    • #35201 (Refactor: Updated signMessage to use util::Expected and removed SigningResult::OK by kevkevinpal)
    • #35182 (Replace libevent with our own HTTP and socket-handling implementation by pinheadmz)
    • #35105 (Refactor: Updated TransactionError to use util::Expected and removed TransactionError:OK by kevkevinpal)
    • #35084 (ipc: Support for windows support by ryanofsky)
    • #35043 (refactor: Properly return from ThreadSafeQuestion signal + btcsignals follow-ups by maflcko)
    • #35037 (ipc: support per-address max-connections options on -ipcbind by enirox001)
    • #35011 (ci, iwyu: Fix warnings in src/script and treat them as errors by BrandonOdiwuor)
    • #34995 (ci, iwyu: Fix warnings in src/common and treat them as errors by hebasto)
    • #34909 (wallet, refactor: modularise wallet by extracting out legacy wallet migration by rkrux)
    • #34778 (logging: rewrite macros to add ratelimit option, avoid unused strprintf, clarify confusing errors by ryanofsky)
    • #34644 (mining: add submitBlock to IPC Mining interface by w0xlt)
    • #34603 (wallet: Fix detection of symlinks on Windows by achow101)
    • #34533 (wallet: resubmit transactions with private broadcast if enabled by vasild)
    • #34514 (refactor: remove unnecessary std::move for a few trivially copyable types by l0rinc)
    • #34411 ([POC] Full Libevent removal by fanquake)
    • #34038 (logging: replace -loglevel with -trace, expose trace logging via RPC by ajtowns)
    • #33966 (refactor: disentangle miner startup defaults from runtime options by Sjors)
    • #33922 (mining: add getMemoryLoad() and track template non-mempool memory footprint by Sjors)
    • #33727 (zmq: Log bind error at Error level, abort startup on init error by isrod)
    • #33421 (node: add BlockTemplateCache by ismaelsadeeq)
    • #33117 (Interfaces: Expose UTXO Snapshot Loading and Add Progress Notifications by D33r-Gee)
    • #32966 (Silent Payments: Receiving by Eunovo)
    • #32387 (ipc: add windows support by ryanofsky)
    • #30343 (wallet, logging: Replace WalletLogPrintf() with LogInfo() by ryanofsky)
    • #29256 (log, refactor: Allow log macros to accept context arguments 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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. ajtowns commented at 5:08 PM on March 11, 2026: contributor

    Split off from #34038

  5. DrahtBot added the label Needs rebase on Mar 20, 2026
  6. ajtowns force-pushed on Mar 20, 2026
  7. DrahtBot removed the label Needs rebase on Mar 20, 2026
  8. ajtowns force-pushed on Mar 24, 2026
  9. DrahtBot added the label Needs rebase on Mar 31, 2026
  10. ajtowns force-pushed on Apr 2, 2026
  11. DrahtBot removed the label Needs rebase on Apr 2, 2026
  12. DrahtBot added the label Needs rebase on Apr 9, 2026
  13. ajtowns force-pushed on Apr 9, 2026
  14. DrahtBot removed the label Needs rebase on Apr 9, 2026
  15. DrahtBot added the label Needs rebase on Apr 23, 2026
  16. util/stdmutex: Drop StdLockGuard 904c0d07bb
  17. ajtowns force-pushed on Apr 23, 2026
  18. DrahtBot removed the label Needs rebase on Apr 23, 2026
  19. DrahtBot added the label CI failed on Apr 23, 2026
  20. DrahtBot removed the label CI failed on Apr 23, 2026
  21. sedited approved
  22. sedited commented at 10:57 AM on May 11, 2026: contributor

    lgtm ACK 2077e57eb0107acfeb09846899c7e7ae7f77014e

    This is bit of a laundry list, and the conflicts are unfortunate, but better to get this done sooner rather than later.

  23. in src/logging.cpp:546 in b408c2cde2
     542 | +            LogPrint_({
     543 | +                .category = BCLog::ALL,
     544 | +                .level = Level::Warning,
     545 | +                .should_ratelimit = true,
     546 | +                .source_loc = SourceLocation{__func__},
     547 | +                .message = "Failed to shrink debug log file: fseek(...) failed"
    


    maflcko commented at 1:33 PM on May 13, 2026:

    style-nit in b408c2cde2500524a243c6b98d20f27f158e2f5a: Missing trailing comma

  24. in src/util/log.h:113 in 8d1edeb3fa
     109 | @@ -110,15 +110,15 @@ using Level = util::log::Level;
     110 |  
     111 |  // Allow __func__ to be used in any context without warnings:
     112 |  // NOLINTNEXTLINE(bugprone-lambda-function-name)
     113 | -#define LogPrintLevel_(category, level, ...) util::log::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
     114 | +#define detail_LogPrintLevel_(category, level, ...) util::log::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
    


    maflcko commented at 2:49 PM on May 13, 2026:

    nit in 8d1edeb3fa384a3f3223c8c7b06631f9ff75917c: The name seems a bit odd, why does it mention Level but not Category in the name? I think a better name would describe what the macro does and why it is needed: The macro will log; and the macro is needed (as opposed to just inlining it in the only 4 places it is used) because clang-tidy would complain about the source location in lambdas instead.

    So wdyt about detail_LogWithSrcLoc(category, level, ...)? The fact that it accepts a level (and category) should already be clear from the context.

  25. in src/util/log.h:137 in 12035b9a73
     138 | -        }                                                              \
     139 | +#define detail_LogIfCategoryAndLevelEnabled(category, shouldlog, level, ...) \
     140 | +    do { \
     141 | +        if (shouldlog(category)) { \
     142 | +            detail_LogPrintLevel_((category), (level), util::log::NO_RATE_LIMIT, __VA_ARGS__); \
     143 | +        } \
    


    maflcko commented at 3:09 PM on May 13, 2026:

    nit in 12035b9a73b118ee9916a5ad7aa8d25379a114b3: Reflowing the escapes violates the AlignEscapedNewlines setting and I find it minimally harder to read. I'd say either leave untouched lines as-is, or reflow according to clang-format with the current AlignEscapedNewlines setting.

  26. in src/util/log.h:74 in 12035b9a73
      72 | +/** Return whether messages with specified category should be debug logged.
      73 | + * Applications using the logging library need to provide this. */
      74 | +bool ShouldDebugLog(Category category);
      75 | +
      76 | +/** Return whether messages with specified category should be trace logged.
      77 | + * Applications using the logging library need to provide this. */
    


    maflcko commented at 3:12 PM on May 13, 2026:

    nit in 12035b9a73b118ee9916a5ad7aa8d25379a114b3: I find it a bit ugly style-wise to use the /** doxygen comments, but then try to pack it as tightly as possible with lines starting at different indents.

    My recommendation would be to use the /// doxygen comment:

    /// Return whether messages with specified category should be trace logged.
    /// Applications using the logging library need to provide this.
    
  27. maflcko commented at 3:44 PM on May 13, 2026: member

    lgtm. Left style nits, but they are just my preference and not important.

    review ACK 2077e57eb0107acfeb09846899c7e7ae7f77014e 😶

    <details><summary>Show signature</summary>

    Signature:

    untrusted 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}"
    RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
    trusted comment: review ACK 2077e57eb0107acfeb09846899c7e7ae7f77014e 😶
    YrtXvZICcGGKWTWGiUflMfnKMK81dgzri+QgpUdu1QX926GX6nBhNMdlLYf4mqzaeTLgUt9oBE12LULE3QzRAQ==
    

    </details>

  28. logging: Protect ShrinkDebugFile by m_cs
    We should not be logging while shrinking the debug file, so make sure
    that's true by using our mutex.
    72e92d67df
  29. util/log: Provide util::log::NO_RATE_LIMIT to avoid rate limits f69d1ae56d
  30. util/log: Rename LogPrintLevel_ into detail_ namespace
    After the previous commit, LogPrintLevel_ is only used to implement
    other macros.
    58113e5833
  31. logging: Move GetLogCategory into Logger class abea304dd6
  32. util/log, logging: Provide ShouldDebugLog and ShouldTraceLog instead of a generic ShouldLog 34332dba2f
  33. scripted-diff: logging: Drop LogAcceptCategory
    -BEGIN VERIFY SCRIPT-
    sed -i 's/LogAcceptCategory(\(.*\), [a-zA-Z:]*::Level::Debug)/util::log::ShouldDebugLog(\1)/g' $(git grep -l LogAcceptCategory -- '*.cpp')
    sed -i 's/LogAcceptCategory(\(.*\), [a-zA-Z:]*::Level::Trace)/util::log::ShouldTraceLog(\1)/g' $(git grep -l LogAcceptCategory -- '*.cpp')
    sed -i '/Return true if log accepts specified category/,/^$/d' src/logging.h
    -END VERIFY SCRIPT-
    611878b46f
  34. IWYU fixes
    Add missing includes of logging.h in preparation for the next commit,
    switching to util/log.h. Also removes some unnecessary util/check.h
    includes that CI complains about.
    57d7495fe5
  35. logging: use util/log.h where possible
    Replace usage of logging.h with util/log.h where it
    suffices.
    02b2c41103
  36. ajtowns force-pushed on May 15, 2026
  37. ajtowns commented at 5:47 PM on May 15, 2026: contributor

    Nits picked

  38. DrahtBot added the label CI failed on May 15, 2026
  39. maflcko commented at 7:50 AM on May 16, 2026: member

    Only change is some style nits, thx

    review ACK 02b2c41103435d8dbaa77a526e484066471b2b8c 📅

    <details><summary>Show signature</summary>

    Signature:

    untrusted 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}"
    RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
    trusted comment: review ACK 02b2c41103435d8dbaa77a526e484066471b2b8c 📅
    /VKzcjmOHGi8cwRym0eCrtEEUdWkBXmK8wv+or/WEMHHcrvJgM6/eJ8wLcb7ht/45P/JxokQ/1bQ0TQFxrH4Dg==
    

    </details>

  40. DrahtBot requested review from sedited on May 16, 2026
  41. DrahtBot removed the label CI failed on May 16, 2026
  42. sedited approved
  43. sedited commented at 9:25 AM on May 16, 2026: contributor

    Re-ACK 02b2c41103435d8dbaa77a526e484066471b2b8c

  44. fanquake commented at 8:09 AM on May 18, 2026: member
  45. in src/util/log.h:98 in f69d1ae56d
      91 | @@ -92,17 +92,35 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
      92 |          .message = std::move(log_msg)});
      93 |  }
      94 |  
      95 | +template <typename... Args>
      96 | +inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
      97 | +{
      98 | +    return LogPrintFormatInternal_(std::move(source_loc), flag, level, /*should_ratelimit=*/true, fmt, args...);
    


    l0rinc commented at 9:19 AM on May 18, 2026:

    f69d1ae util/log: Provide util::log::NO_RATE_LIMIT to avoid rate limits:

    nit: SourceLocation is trivially copyable, so we don't need to move it, see: https://github.com/bitcoin/bitcoin/pull/34514/changes/f5e92d79cccecec4cf5e0d6d8ea7b0638e5397a2#diff-c75b427ca21222164fa8e95d82f29fefa6b60044d0510fe85f4e06e57cdc154bR82

    Should probably done in the above PR instead (after this is merged).

    <details><summary>Pass source locations by value</summary>

    diff --git a/src/util/log.h b/src/util/log.h
    --- a/src/util/log.h	(revision 64cfc6da7b95cf801dfad60df01d757563edcc1c)
    +++ b/src/util/log.h	(revision ee74530a08ff7a145ef0a9fdf72cbc27e759e321)
    @@ -82,7 +82,7 @@
     namespace detail {
     
     template <typename... Args>
    -inline void LogPrintFormat(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    +inline void LogPrintFormat(SourceLocation source_loc, BCLog::LogFlags flag, util::log::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     {
         std::string log_msg;
         try {
    @@ -94,20 +94,20 @@
             .category = flag,
             .level = level,
             .should_ratelimit = should_ratelimit,
    -        .source_loc = std::move(source_loc),
    +        .source_loc = source_loc,
             .message = std::move(log_msg)});
     }
     
     template <typename... Args>
    -inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    +inline void LogPrintFormatInternal(SourceLocation source_loc, BCLog::LogFlags flag, util::log::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     {
    -    LogPrintFormat(std::move(source_loc), flag, level, /*should_ratelimit=*/true, fmt, args...);
    +    LogPrintFormat(source_loc, flag, level, /*should_ratelimit=*/true, fmt, args...);
     }
     
     template <typename... Args>
    -inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::log::NoRateLimitTag, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    +inline void LogPrintFormatInternal(SourceLocation source_loc, BCLog::LogFlags flag, util::log::Level level, util::log::NoRateLimitTag, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     {
    -    LogPrintFormat(std::move(source_loc), flag, level, /*should_ratelimit=*/false, fmt, args...);
    +    LogPrintFormat(source_loc, flag, level, /*should_ratelimit=*/false, fmt, args...);
     }
     
     } // namespace detail
    

    </details>


    ajtowns commented at 11:10 PM on May 21, 2026:

    From https://en.cppreference.com/cpp/utility/source_location

    It is unspecified whether the copy/move constructors and the copy/move assignment operators of std::source_location are trivial and/or constexpr.


    l0rinc commented at 6:58 AM on May 22, 2026:

    In our case, they seem to be trivially copyable; we're explicitly checking it with

    static_assert(std::is_trivially_copyable_v<SourceLocation>); // Document why we're not using std::move for these types
    

    But to make it uncontroversial, I have removed this from https://github.com/bitcoin/bitcoin/pull/34514

  46. in doc/developer-notes.md:767 in f69d1ae56d
     762 | @@ -764,6 +763,13 @@ Note that the format strings and parameters of `LogDebug` and `LogTrace`
     763 |  are only evaluated if the logging category is enabled, so you must be
     764 |  careful to avoid side-effects in those expressions.
     765 |  
     766 | +While `LogInfo`, `LogWarning` and `LogError` messages should be rare,
     767 | +in case there are circumstances where they are not, those messages
    


    l0rinc commented at 9:22 AM on May 18, 2026:

    f69d1ae util/log: Provide util::log::NO_RATE_LIMIT to avoid rate limits:

    This wording was a bit hard to parse:

    in case there are circumstances where they are not

    Could this be shortened to:

    in case they are not

  47. in src/util/log.h:104 in f69d1ae56d
      99 | +}
     100 | +
     101 | +template <typename... Args>
     102 | +inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::log::NoRateLimitTag, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     103 | +{
     104 | +    return LogPrintFormatInternal_(std::move(source_loc), flag, level, /*should_ratelimit=*/false, fmt, args...);
    


    l0rinc commented at 9:24 AM on May 18, 2026:

    f69d1ae util/log: Provide util::log::NO_RATE_LIMIT to avoid rate limits:

    nit: I find it a bit confusing that after the existing *Internal suffix, this adds another internal marker via the trailing _.

    Could we hide the helper behind a util::log::detail namespace instead? For example, the bool-taking helper could be renamed to LogPrintFormat, while the macro-facing overloads stay as LogPrintFormatInternal under util::log::detail. That would make the implementation boundary explicit without suffix stacking.

    diff --git a/src/util/log.h b/src/util/log.h
    --- a/src/util/log.h	(revision 02b2c41103435d8dbaa77a526e484066471b2b8c)
    +++ b/src/util/log.h	(revision 7d96b8db4fa1f1e4190aa22ae1a328f52a4c637f)
    @@ -79,8 +79,10 @@
     /** Send message to be logged. Applications using the logging library need to provide this. */
     void Log(Entry entry);
     
    +namespace detail {
    +
     template <typename... Args>
    -inline void LogPrintFormatInternal_(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    +inline void LogPrintFormat(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     {
         std::string log_msg;
         try {
    @@ -99,14 +101,16 @@
     template <typename... Args>
     inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     {
    -    return LogPrintFormatInternal_(std::move(source_loc), flag, level, /*should_ratelimit=*/true, fmt, args...);
    +    return LogPrintFormat(std::move(source_loc), flag, level, /*should_ratelimit=*/true, fmt, args...);
     }
     
     template <typename... Args>
     inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::log::NoRateLimitTag, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
     {
    -    return LogPrintFormatInternal_(std::move(source_loc), flag, level, /*should_ratelimit=*/false, fmt, args...);
    +    return LogPrintFormat(std::move(source_loc), flag, level, /*should_ratelimit=*/false, fmt, args...);
     }
    +
    +} // namespace detail
     } // namespace util::log
     
     namespace BCLog {
    @@ -116,7 +120,7 @@
     
     // Allow __func__ to be used in any context without warnings:
     // NOLINTNEXTLINE(bugprone-lambda-function-name)
    -#define detail_LogWithSrcLoc(category, level, ...) util::log::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
    +#define detail_LogWithSrcLoc(category, level, ...) util::log::detail::LogPrintFormatInternal(SourceLocation{__func__}, category, level, __VA_ARGS__)
     
     // Log unconditionally. Uses basic rate limiting to mitigate disk filling attacks.
     // Be conservative when using functions that unconditionally log to debug.log!
    

    ajtowns commented at 3:17 AM on May 22, 2026:

    Added a commit for this at #35355; it moves the should_ratelimit bool to the first argument (prior to SourceLocation&&) to ensure there's no ambiguity in function resolution.

  48. in src/util/log.h:83 in 02b2c41103
      88 | -using Level = util::log::Level;
      89 | -} // namespace BCLog
      90 |  
      91 |  template <typename... Args>
      92 | -inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, BCLog::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
      93 | +inline void LogPrintFormatInternal_(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, bool should_ratelimit, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    


    l0rinc commented at 12:20 PM on May 18, 2026:

    nit: we're already in namespace util::log here (and a few other places):

    inline void LogPrintFormatInternal_(SourceLocation&& source_loc, BCLog::LogFlags flag, Level level, bool should_ratelimit, ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    

    ajtowns commented at 2:31 AM on May 22, 2026:

    Had a look at these, but util::log::Level seems clearer/more consistent than just Level to me, and I don't think dropping the unnecessary prefixes would really help much.

  49. in src/logging.cpp:617 in 02b2c41103
     611 | @@ -604,9 +612,14 @@ bool BCLog::Logger::SetCategoryLogLevel(std::string_view category_str, std::stri
     612 |      return true;
     613 |  }
     614 |  
     615 | -bool util::log::ShouldLog(Category category, Level level)
     616 | +bool util::log::ShouldDebugLog(Category category)
     617 | +{
     618 | +    return LogInstance().WillLogCategoryLevel(static_cast<BCLog::LogFlags>(category), util::log::Level::Debug);
    


    l0rinc commented at 12:45 PM on May 18, 2026:

    nit: now that we have these specializations does it still make sense to keep WillLogCategoryLevel public? We could we expose WillLogCategoryDebug / WillLogCategoryTrace as the caller-facing methods and make WillLogCategoryLevel private.


    ajtowns commented at 11:19 PM on May 21, 2026:

    I have a commit in the followup branch to drop that entirely https://github.com/ajtowns/bitcoin/commits/202512-log-atomic/

  50. in src/util/log.h:100 in 02b2c41103
      95 | @@ -92,35 +96,51 @@ inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags
      96 |          .message = std::move(log_msg)});
      97 |  }
      98 |  
      99 | +template <typename... Args>
     100 | +inline void LogPrintFormatInternal(SourceLocation&& source_loc, BCLog::LogFlags flag, util::log::Level level, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
    


    l0rinc commented at 12:55 PM on May 18, 2026:

    Is there any reason for return-ing in these void methods?


    ajtowns commented at 11:21 PM on May 21, 2026:

    Not really; it acts similar to a [[nodiscard]] on the delegated-to function.

  51. in src/logging.cpp:541 in 02b2c41103
     536 | @@ -535,7 +537,14 @@ void BCLog::Logger::ShrinkDebugFile()
     537 |          // Restart the file with some of the end
     538 |          std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
     539 |          if (fseek(file, -((long)vch.size()), SEEK_END)) {
     540 | -            LogWarning("Failed to shrink debug log file: fseek(...) failed");
     541 | +            // LogWarning, except with m_cs held
     542 | +            LogPrint_({
    


    l0rinc commented at 1:00 PM on May 18, 2026:

    https://corecheck.dev/bitcoin/bitcoin/pulls/34806 complains the ShrinkDebugFile changes are uncovered new code


    ajtowns commented at 11:22 PM on May 21, 2026:

    That seems to just be saying that ShrinkDebugFile is entirely uncovered by tests.

  52. l0rinc approved
  53. l0rinc commented at 1:10 PM on May 18, 2026: contributor

    untested ACK 02b2c41103435d8dbaa77a526e484066471b2b8c

    I left a few suggestions, but the code looks fine to me.

    nit: The last two include-only commits could probably be merged - and I found a few other similar ones that could be added.

  54. ryanofsky approved
  55. ryanofsky commented at 9:12 PM on May 18, 2026: contributor

    Light code review ACK 02b2c41103435d8dbaa77a526e484066471b2b8c. Overall this is a nice collection of fixes.

    The only thing I'd flag here is that I don't think it makes sense to replace LogAcceptCategory calls with ShouldTraceLog and ShouldDebugLog calls. Reasons I'd cite for this:

    • LogAcceptCategory is meant to be called by application code and be a stable API that doesn't depend on the logging backend. By contrast ShouldLog/Log are hooks added recently that can be implemented by different logging backends and can change or be replaced as needed to implement features or improve efficiency.

    • LogAcceptCategory is a better API than ShouldDebugLog and ShouldTraceLog because it acknowledges the relationship between log levels. For example, it would look broken to see LogTrace calls used in inside a if ShouldDebugLog() block, even though in order for trace calls to be visible, debug logs have to be enabled. By contrast, a LogAcceptCategory call passing a Level value would look obvious because log levels have an ordered relationship.

    • IMO, It is unfortunate to see log level names baked into more function names, and to see functions duplicated and implemented in different ways depending on log level. We already have a number of undocumented untested differences between log levels (cleaned up in #34778) and introducing more duplicate functions invites more problems of this kind in the future.

    My recommendation to address these concerns would be to drop two commits 34332dba2f6f6892859ecb62daa9a2add76ae05e and 611878b46f702f1844e4c89b7fd36a9a54e09167 from this PR, and replace them with fb57ce24cc0d24a64a4b2f7b8fdeb921db1ed999 so the later include/IWYU improvements can be kept.

    (The replacement commit fb57ce24cc0d24a64a4b2f7b8fdeb921db1ed999 was originally implemented by stickies in #34374 and I almost included it in #34465, but dropped it to keep that PR small. It is currently part of #34778, so would helpful for that PR, as well.)

  56. sedited commented at 7:24 AM on May 20, 2026: contributor

    @ajtowns do you want to address the nits here?

  57. ajtowns commented at 11:35 PM on May 21, 2026: contributor

    The only thing I'd flag here is that I don't think it makes sense to replace LogAcceptCategory calls with ShouldTraceLog and ShouldDebugLog calls. Reasons I'd cite for this:

    Using ShouldDebugLog and ShouldTraceLog removes the possibility of making unnecessary/non-sensical queries (eg LogAcceptCategory(BCLog::LEVELDB, util::log::level::INFO)) and turns invalid function calls into a structural guarantee/compile-time error rather than a runtime error (bool rate_limit{level >= BCLog::Level::Info}; Assume(!rate_limit);).

    In general, please stop trying to turn every logging PR into a new front on your war to revert the changes from #28318 [ref], it is completely unprofessional. If you want to have a productive discussion on the topic #30486 remains available for that.

    • LogAcceptCategory is a better API than ShouldDebugLog and ShouldTraceLog because it acknowledges the relationship between log levels. For example, it would look broken to see LogTrace calls used in inside a if ShouldDebugLog() block, even though in order for trace calls to be visible, debug logs have to be enabled.

    If just you use ShouldTraceLog() it will correctly check this. I don't think it's a problem that doing something stupid looks broken.

    With a followup PR to replace m_log_level and m_category_log_levels with an atomic<CategoryMask> m_log_trace both ShouldDebugLog() and ShouldTraceLog() become a direct atomic lookup on a single integer that can be done directly at the logging site without futher indirection, keeping disabled logging options as fast as possible.

  58. in src/util/log.h:73 in 34332dba2f
      67 | @@ -68,9 +68,13 @@ struct Entry {
      68 |      std::string message;
      69 |  };
      70 |  
      71 | -/** Return whether messages with specified category and level should be logged. Applications using
      72 | - * the logging library need to provide this. */
      73 | -bool ShouldLog(Category category, Level level);
      74 | +/// Return whether messages with specified category should be debug logged.
      75 | +/// Applications using the logging library need to provide this.
      76 | +bool ShouldDebugLog(Category category);
    


    ryanofsky commented at 2:19 AM on May 22, 2026:

    In commit "util/log, logging: Provide ShouldDebugLog and ShouldTraceLog instead of a generic ShouldLog" (34332dba2f6f6892859ecb62daa9a2add76ae05e)

    Note there is a minor loss of type checking here because util::log::Category is a uint64_t, not a LogFlags value. This seems like another reason not to try to use an opaque category type.

  59. in src/util/log.h:77 in 34332dba2f
      75 | +/// Applications using the logging library need to provide this.
      76 | +bool ShouldDebugLog(Category category);
      77 | +
      78 | +/// Return whether messages with specified category should be trace logged.
      79 | +/// Applications using the logging library need to provide this.
      80 | +bool ShouldTraceLog(Category category);
    


    ryanofsky commented at 2:21 AM on May 22, 2026:

    In commit "util/log, logging: Provide ShouldDebugLog and ShouldTraceLog instead of a generic ShouldLog" (34332dba2f6f6892859ecb62daa9a2add76ae05e)

    Would be good to document that if this returns true ShouldDebugLog will also return true.

  60. in src/util/log.h:134 in 34332dba2f
     131 | @@ -128,16 +132,15 @@ using Level = util::log::Level;
     132 |  // Log by prefixing the output with the passed category name and severity level. This logs conditionally if
     133 |  // the category is allowed. No rate limiting is applied, because users specifying -debug are assumed to be
     134 |  // developers or power users who are aware that -debug may cause excessive disk usage due to logging.
     135 | -#define detail_LogIfCategoryAndLevelEnabled(category, level, ...)      \
     136 | -    do {                                                               \
     137 | -        if (util::log::ShouldLog((category), (level))) {               \
     138 | -            Assume((level) < util::log::Level::Info); /*Only called with the levels below*/ \
    


    ryanofsky commented at 2:34 AM on May 22, 2026:

    In commit "util/log, logging: Provide ShouldDebugLog and ShouldTraceLog instead of a generic ShouldLog" (34332dba2f6f6892859ecb62daa9a2add76ae05e)

    This Assume does not seem good to get rid of. Now there is isn't anything to prevent from this being called with other levels. It also makes it less clear why it is safe to disable rate-limiting here. (There's nothing backing up "users specifying -debug" comment above.)

    This change also makes the lack of checking slightly worse because now the level is passed twice in two different arguments and there is also no check that the arguments are consistent.

    Would suggest at least keeping the existing Assume, if not adding a second Assume to make sure the parameters are consistent, or refactoring to consolidate them.

  61. ryanofsky approved
  62. ryanofsky commented at 3:00 AM on May 22, 2026: contributor

    Code review ACK 02b2c41103435d8dbaa77a526e484066471b2b8c! Overall a lot of nice improvements here.

    re: #34806 (comment)

    Using ShouldDebugLog and ShouldTraceLog removes the possibility of making unnecessary/non-sensical queries (eg LogAcceptCategory(BCLog::LEVELDB, util::log::level::INFO))

    This isn't nonsensical? It's makes sense to have a function that tells you when logging will be enabled for a particular category at a particular level. As you know, this works currently and always returns true (although more ideally it might return false when -noprinttoconsole -nodebuglogfile are used or when DisableLogging is called by tests or kernel applications).

    But I do understand your reasoning that application code should only be allowed to be make calls at Debug and Trace levels, not other levels. I don't really agree with this reasoning, because it leads to complexity that is technically unnecessary, but I understand the idea if applications are allowed to know when Info logs are disabled, it could lead to unnoticed differences in behavior and bugs, so Info and higher level logging code should always be executed.

    (BTW, this restriction you want is actually a perfect illustration of why I was saying ShouldLog and LogAcceptCategory should be separate functions, because needs of logging applications and backends are different. But it's also ok to repurpose ShouldLog for application use and add a different backend hook if needed.)

    turns invalid function calls into a structural guarantee/compile-time error rather than a runtime error (bool rate_limit{level >= BCLog::Level::Info}; Assume(!rate_limit);).

    I see the point you are getting at but this PR just deletes the Assume even though there is no rationale for doing so. It would be counterproductive to shill here, but #34778 actually gets rid of this fragility in a structural and DRY way.

    In general, please stop trying to turn every logging PR into a new front on your war to revert the changes from #28318 [ref], it is completely unprofessional.

    I forgive you and love you AJ, but this is an insane comment. I genuinely think #28318 was a major improvement to the logging framework, and have praised the parts of it I like, while criticizing relatively minor aspects of it I didn't like. Since that PR was merged (I didn't see it before it was merged) I tried to remove some restrictions it added which I felt were unnecessary and added complexity, but in every case where you pointed at a specific rationale for those restrictions, I've backed down and respected them, even adding tests and documentation for them, while working around them in my PRs.

    I have reviewed your PRs, and ACKed your code for correctness even when it did things I disagreed with. All of my criticisms have been technical, not personal. They have focused on specific harms and tradeoffs instead of making sweeping claims. They have been constructive, not just pointing out problems I see, but pointing out solutions that are compatible with your goals as I understand them.

    It is true to say that in immediate aftermath of #28318 I was too dismissive of your concerns and did not yet understand them. But it's probably been 2 years since I've made an even remotely impolite or snarky comment, and I don't see a good reason we shouldn't be able to work together productively going forward.

    If you want to have a productive discussion on the topic #30486 remains available for that.

    I don't see a specific relationship between that issue and anything here, but I can take a look.

    If just you use ShouldTraceLog() it will correctly check this. I don't think it's a problem that doing something stupid looks broken.

    I don't think this behavior is stupid, but maybe I didn't describe it well. The scenario is when you want to turn on some additional computation/data accumulation/tracking when level debugging is on. And you want to show some of that information with LogDebug statements, and even more information with LogTrace statement. Conditioning both on Debug being enabled looks broken. Conditioning on Debug || Trace works but is misleading. Conditioning on Level::Debug is transparent and natural. This is not an important point, and it mostly bothers me because it seems unnecessarily opaque. But I understand the reasons why you favor this approach.

    With a followup PR to replace m_log_level and m_category_log_levels with an atomic<CategoryMask> m_log_trace both ShouldDebugLog() and ShouldTraceLog() become a direct atomic lookup on a single integer that can be done directly at the logging site without futher indirection, keeping disabled logging options as fast as possible.

    FWIW, that doesn't depend on anything in this PR and #35322 implements this.

  63. ryanofsky merged this on May 22, 2026
  64. ryanofsky closed this on May 22, 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-06-01 16:51 UTC

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