{
 "number": 34778,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/34778",
 "title": "logging: rewrite macros to enforce restrictions at compile-time, improve efficiency and usability",
 "author": "ryanofsky",
 "author_association": "MEMBER",
 "created_at": "2026-03-09T15:28:25Z",
 "updated_at": "2026-09-17T07:41:48Z",
 "age_days": 192,
 "draft": false,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "f0929e1b781af5012d835f78a8b54054fb5cb21e",
 "head_ref": "pr/relog",
 "head_repo": "ryanofsky/bitcoin",
 "head_history": [
  {
   "t": "2026-04-01T17:37:20Z",
   "sha": "fbc43e5b66a9e613499249b29bb6a74de5507c03"
  },
  {
   "t": "2026-04-03T11:57:18Z",
   "sha": "31612a7f5f0d197bdc4a9747ad9e7509bf693d7d"
  },
  {
   "t": "2026-05-06T09:17:26Z",
   "sha": "0c090593e8bdbdd3f65ea12aa1177ebc3d22d86a"
  },
  {
   "t": "2026-05-26T20:14:42Z",
   "sha": "f0929e1b781af5012d835f78a8b54054fb5cb21e"
  }
 ],
 "additions": 275,
 "deletions": 113,
 "changed_files": 6,
 "commit_count": 6,
 "size_bucket": "M",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_nack": [
     {
      "login": "ajtowns",
      "url": "https://github.com/bitcoin/bitcoin/pull/34778#issuecomment-4030462014"
     }
    ]
   },
   "conflicts": [
    {
     "number": 35322,
     "title": "logging: streamline Logger state and drop redundant methods",
     "author": "ryanofsky"
    }
   ]
  }
 },
 "acks_parsed": {
  "ajtowns": {
   "kind": "concept_nack",
   "hash": null,
   "t": "2026-03-10T10:46:49Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 1,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "ajtowns",
   "maflcko",
   "sedited"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-05-26T20:14:42Z",
  "last_reviewer_activity": "2026-09-17T07:41:44Z",
  "last_reviewer": "sedited",
  "author_silent_days": 113,
  "waiting_on_author_days": 0,
  "days_since_update": 0
 },
 "refs": {
  "mentioned": [
   30342,
   30343,
   34038,
   34374,
   34806,
   34865
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 30343,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "wallet, logging: Replace WalletLogPrintf() with LogInfo()"
   },
   {
    "number": 30342,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "kernel, logging: Pass Logger instances to kernel objects"
   },
   {
    "number": 34038,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "logging: replace -loglevel with -trace, expose trace logging via RPC"
   },
   {
    "number": 34374,
    "type": "pull",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "kernel: use struct-based logging and simplify logging interface"
   },
   {
    "number": 34806,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-05-22",
    "title": "refactor: logging: Various API improvements"
   },
   {
    "number": 34865,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-04-23",
    "title": "logging: better use of log::Entry internally"
   }
  ],
  "conflicts": [
   35322
  ]
 },
 "stack": {
  "shares_commits_with": [
   29256,
   30342,
   30343
  ],
  "based_on": [],
  "base_for": [
   29256,
   30342,
   30343
  ]
 },
 "review_paths": [
  "src/validation.cpp"
 ],
 "body": "This PR is an internal cleanup for `util/log.h` that fixes several problems with the logging macros defined there.\n\nThe main change is replacing the internal `detail_LogWithSrcLoc` macro with a `LOG_EMIT` macro. It makes all the external logging macros (`LogDebug`, `LogInfo`, etc.) call `LOG_EMIT`, eliminating inconsistencies, improving efficiency, and producing clearer compiler errors when called incorrectly.\n\nSpecific problems this PR fixes:\n\n- Current logging macros duplicate logic and have undocumented, untested differences. For example, some macros evaluate their arguments when logging is disabled and others do not. By constrast, the `LOG_EMIT` macro implements logging logic in one place, preventing hidden inconsistencies.\n\n- Current logging macros produce hard to decipher syntax errors when category arguments are specified but not allowed, or required but not provided. Now all logging macros produce clear `static_assert` errors indicating whether to add or remove category arguments.\n\n- Current `LogInfo`, `LogWarning`, and `LogError` macros generate log entries and call `util::log::Log(Entry)` even when logging is disabled. `LOG_EMIT` avoids this overhead, which is probably minor but could improve performance in some kernel applications and fuzzing.\n\n- Current `detail_LogWithSrcLoc` macro is dangerous to call because because it does not check for inconsistent or invalid arguments. For example, calling it always bypasses ratelimiting without a check to prevent this. (Previously there was a runtime check, but it was removed without justification in 34332dba2f6f6892859ecb62daa9a2add76ae05e). New `LOG_EMIT` macro is compile-time safe and all the same restrictions as other macros.\n\n- Having multiple implementations of logging macros makes it difficult to add new logging features (see below), because it requires changing many macros and adding separate macro arguments for each feature. Having a single core `LOG_EMIT` macro taking a single compile-time `options` argument makes it possible to add new features cleanly.\n\nIndividual commits also implement other improvements: adding missing test coverage and removing misleading `Entry::should_ratelimit` field which is stored in buffered log messages after rate-limiting has been applied, and has no effect.\n\n---\n\n#### Possible followups\n\nThis PR does not add any new logging features. It is purely an internal cleanup that fixes the problems listed above. However, it is worth noting that this PR could make it easier to add logging features in the future. For example:\n\n1. New logging options could be added. Examples: `.stacktrace = true` to log the current stack trace, `.exception = true` to log the current exception, `.impossible = true` to indicate an impossible condition and halt fuzzing or request a bug report, `.log_once = true` to log at most once from this source location, `.log_every = 60m` to log at most once per hour, `.dedup = true` to drop duplicste messages, etc.\n\n2. External macros like `LogInfo` and `LogDebug` could accept these options. Example: f5ca95b1e610ebad7063143ddef98fc318251bc4\n\n3. Context information could be added to log messages, e.g., wallet names, chainstate names, or request IDs to distinguish logs from paralell requests. Example: [#30343](https://github.com/bitcoin/bitcoin/pull/30343)\n\n4. Non-global logging streams could also be supported. For example, kernel functions could accept optional logger arguments instead of always writing to the global logger. Example: [#30342](https://github.com/bitcoin/bitcoin/pull/30342)",
 "commits": [
  {
   "sha": "963ed23bc8c466188c2be7553ae383cf182c24b4",
   "date": "2026-05-26T12:39:03Z",
   "message": "log test: verify log argument evaluation semantics\n\nTest that LogInfo/LogWarning/LogError always evaluate their arguments\neven when logging is disabled.\n\najtowns pointed out this behavior was important and could affect non-logging\ncode if changed in\nhttps://github.com/bitcoin/bitcoin/pull/34374#discussion_r2734793117\n\nCo-authored-by: l0rinc <pap.lorinc@gmail.com>"
  },
  {
   "sha": "3ea9b7cb10f0667d7fd1d2e8b4e25e8aea9932b3",
   "date": "2026-05-26T12:39:03Z",
   "message": "log test: add some test coverage on LogAcceptCategory\n\nCo-authored-by: Ryan Ofsky <ryan@ofsky.org>"
  },
  {
   "sha": "9c509ca53c0185a8f5b96c2a5aa3a5b7d73045a7",
   "date": "2026-05-26T12:39:03Z",
   "message": "log test: Add test for all accepted logging arguments\n\nAdd new logging test to call macros with all allowed combinations of macro\narguments.\n\nThe new test replaces a less comprehensive test that doesn't cover log\nstatements without format arguments. It's also moved to the top of the test\nsuite because it's a good illustration of what typical log prints look like,\nwhat logging calls are allowed and disallowed, and what the resulting log\noutput looks like."
  },
  {
   "sha": "98f3bd6242d999191f442271a77eb8cac7949ca1",
   "date": "2026-05-26T12:39:03Z",
   "message": "log refactor: Ensure categories are not logged at info and higher levels\n\nPreviously this used to be possible through the LogPrintLevel call but now that\ncall is removed, this change is just an internal refactoring and has no visible\neffect except in tests."
  },
  {
   "sha": "31f9929f3dea586104c0c11d7533385e139bdbdf",
   "date": "2026-05-26T12:39:03Z",
   "message": "log refactor: log macro rewrite\n\nRewrite log macros to fix a number of issues: unnecessary strprintf\ncalls during fuzzing, confusing error messages when macros are called\nwith the wrong arguments, duplicated code with unexplained differences\nand undocumented assumptions.\n\nSince this is a rewrite, reading the new code in log.h first should be clearer\nthan starting from the diff.\n\nSpecific benefits of the new implementation are:\n\n- Functionality is implemented once in a single `LOG_EMIT` macro instead of\n  multiple times in different macros with diverging code paths and unexplained\n  differences.\n\n- Unnecessary `strprintf` calls are now skipped when logging is disabled (in\n  bitcoind when `-noprinttoconsole -nodebuglogfile` options are used, and in\n  tests and kernel applications when DisableLogging is called). This change\n  should not affect bitcoind noticeably, but could speed up fuzz tests calling\n  functions which log.\n\n- Clearer error messages: If you pass a category to a macro which does not\n  accept it, or forget to pass a category to a macro which requires it, you\n  will see a direct message telling you to add or remove the category instead\n  of expanded macro syntax errors.\n\n- Previously it was possible to call `detail_LogWithSrcLoc` with\n  inconsistent or invalid arguments, for example bypassing ratelimiting\n  without it being explicit. New `LOG_EMIT` macro is compile-time safe\n  and enforces the exact same restrictions as other macros.\n\n- Previously \"always evaluate arguments\" behavior at Info and higher levels\n  looked accidental and was undocumented\n  (https://github.com/bitcoin/bitcoin/pull/34374#discussion_r2734793117). Now\n  the behavior is documented and explicit.\n\n- `NO_RATE_LIMIT` special case used to bypass rate limiting is dropped.\n  The `LOG_EMIT` macro can control rate limiting (and other options if\n  they are added in the future) while still using the same ratelimiting\n  defaults as other macros.\n\nCo-Authored-By: Hodlinator <172445034+hodlinator@users.noreply.github.com>\nCo-Authored-By: stickies-v <stickies-v@protonmail.com>"
  },
  {
   "sha": "f0929e1b781af5012d835f78a8b54054fb5cb21e",
   "date": "2026-05-26T12:39:03Z",
   "message": "log refactor: Drop Entry::should_ratelimit field\n\nDrop Entry::should_ratelimit field in favor of Options::ratelimit field.\n\nDropping the Entry::should_ratelimit field makes buffered log messages\nin m_msgs_before_open smaller, and avoids potential confusion because\nthe field is stored after rate limiting has been applied, so just gets\nignored. Conceptually it also makes sense to treat the ratelimit option\nas an input to the logger rather than as an attribute of the message\nbeing logged."
  }
 ],
 "timeline": [
  {
   "t": "2026-03-10T10:46:49Z",
   "kind": "comment",
   "who": "ajtowns",
   "assoc": "MEMBER",
   "text": "Concept NACK to reintroducing a generic `LogPrint`. The `NO_RATE_LIMIT` commit from #34038 has been available for review for three months now, and has had a concept ack for that long."
  },
  {
   "t": "2026-03-10T13:43:13Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "[quoted text omitted]\n\nThat's interesting. #34038 is mostly a logging backend change, changing the RPC interface and command line options. It seems like the no-ratelimit change part of that PR might not be related to the other changes there? (I don't see the connection at least.)\n\nTo compare the two approaches, #34038 syntax looks like:\n\n```c++\nLogInfo(util::log::NO_RATE_LIMIT, \"message\");\n```\n\nwhile syntax here is:\n\n```c++\nLogPrint((.level = util::log::Level::Info, .ratelimit = false), \"message\"),\n```\n\nThere is not much difference between the approaches externally, and they are compatible (this PR could easily support a `NO_RATE_LIMIT` flag if reviewers would prefer that.)\n\nThis bigger goal of this PR is to replace current implementation of the logging macros which is messy and inconsistent with a clean implementation. All preprocessor functionality is implemented in a single macro called [`LogPrint`](https://github.com/ryanofsky/bitcoin/blob/e983d97a9141180f9d06f510f17b87a3333b2954/src/util/log.h#L162-L171), getting rid of the branching code paths at different priority levels [[1]](https://github.com/bitcoin/bitcoin/blob/195306c359ff99f9172d1f1690b124269d3a4a0d/src/util/log.h#L95-L97) [[2]](https://github.com/bitcoin/bitcoin/blob/195306c359ff99f9172d1f1690b124269d3a4a0d/src/util/log.h#L115-L116) that have unexplained differences. The differences are all kept, they are just explicit rather than implicit, with better documentation and tests and stricter enforcement of restrictions.\n\nThe `.ratelimit = true` option is exposed as a side-effect of this refactoring, and the refactoring also allows other options to be implemented cleanly in the future. Examples could be `.log_once=true` `.log_every=24h` `.log_every=60m` `.stack_trace=true` `.dedup = true` etc. I was also thinking of an `.impossible = true` option that could be used to document preconditions & provide better bug reports and output from fuzz & unit test failures. The point is that I think we should make it easy to add logging options and try to implement most options with `constexpr` code instead of macros. And get rid of complication of different macros at different log levels having different implementations.\n\nAnyway I'd be happy to review #34038 and I think the runtime changes there look nice. The NO_RATE_LIMIT flag idea there could be nice. If reviewers like it maybe I could support it here and #34038 could be simpler and only implement the logging backend improvements without making a unrelated change (it would seem) to the logging macros?"
  },
  {
   "t": "2026-03-10T14:30:13Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": null,
   "text": "not sure about using the internal/hidden macro here, after the changes. If someone wants to log at info level, it seems clearer to just call `LogInfo`, instead of using some internal macro with a bunch of options.\n\nAlso, supporting `.ratelimit = false` for other levels doesn't really make sense, and certainly isn't needed by current code at all, so supporting it seems odd.\n\nedit: I see it is needed for one warning log as well. So I guess my main concern is that this will open the gates for the \"wild west\" that we were trying to fix: For example, this new macro may encourage to re-introduce helpers of the form: `[](auto level, auto msg) { LogPrint((.level=level),\"%s\", msg); }`, which will then work incorrectly with regard to rate-limiting (silently dropping warnings/errors, when info logs overflow)"
  },
  {
   "t": "2026-03-10T14:46:16Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/34778#discussion_r2912164572\n\n[quoted text omitted]\nWhen you say odd do you mean the code is doing something it should not do? Or not doing something it should do? For example, It would be easy to add a static assert to prevent ratelimiting being requested at certain levels if you feel that is important. Though I'm not sure why ratelimiting should not be available at different levels (I haven't looked into the rate limiting implementation).\n\nOverall, the idea here is to accept options and pass them along the backend to implement. I imagine the bitcoinkernel backend probably won't support rate limiting at all for example (or at least it doesn't in #34374)"
  },
  {
   "t": "2026-03-10T14:55:03Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "[quoted text omitted]\n\nI've edited my comment to explain one case that will make code more brittle.\n\nI mostly think this should remain internal/hidden, maybe `LogPrintInternalDetail(...)`. Otherwise, devs may think this is fine to use without thinking much about the implicit edges."
  },
  {
   "t": "2026-03-10T15:12:19Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/34778#discussion_r2912164572\n\n[quoted text omitted]\nHmm, I'm confused why someone would do what you are suggesting, but if they did it should be safe and work correctly. The ratelimit [default value](https://github.com/ryanofsky/bitcoin/blob/e983d97a9141180f9d06f510f17b87a3333b2954/src/util/log.h#L55-L59) should be the same as before.\n\nThe point of adding `LogPrint` is to be a safe, single implementation of logging code that other macros can just forward to without their own bespoke logic and special cases.\n\nPlease let me know if I am missing something here. Like I said I haven't actually looked at the ratelimiting implementation. This PR is just forwarding the option. If any unsafe option values are currently accepted, we should definitely prohibit them with a static assert, but I'm not seeing where that could be happening."
  },
  {
   "t": "2026-03-10T15:29:46Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "[quoted text omitted]\n\nWell, you can go back in the git history to find this exact pattern. See 2210feb4466eff1455468f0a25045fce4b89c55d.\n\n[quoted text omitted]\nNo, see 2210feb4466eff1455468f0a25045fce4b89c55d, which fixed this. (You can refer to the commit messages for more details)"
  },
  {
   "t": "2026-03-10T15:48:52Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/34778#discussion_r2912600904\n\n[quoted text omitted]\nThanks for clarifying. For others who may be following, the pattern is shown specifically in f2731676619d14fa4527aa9086fb73078d20f26f and 94c51ae540723f5f648477789c11f6395730ae05 and it is not allowed by this PR. This PR enforces the same restrictions as current code.\n\nE.g. if you try to revert f2731676619d14fa4527aa9086fb73078d20f26f and call `LogPrint((.level = ConvertIPCLogLevel(message.level)) , \"%s\\n\", message.message);` you will see an error because the level is not a compile time constant.\n\n(EDIT: I'd add that I don't see anything inherently wrong with the pattern used in those commits, and no reason it couldn't work well. The previous `LogPrintLevel` implemention just had a bug and was good candidate for removal for other reasons.)"
  },
  {
   "t": "2026-03-10T16:49:39Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "[quoted text omitted]\n\nI don't think this is true. I am sure one can write a similar pattern deriving the level constexpr/consteval.\n\n[quoted text omitted]\nlogging takes the source location, which is then used for other stuff (such as rate limiting or -logsourcelocations). Using the same source location for different logs is brittle in itself. Though, using it for different log levels is doubly brittle. I don't see the need to regress here"
  },
  {
   "t": "2026-03-10T17:41:28Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/34778#discussion_r2913106415\n\n[quoted text omitted]\nCan we slow down and try to work through an example here? I would like to understand the problem you are concerned about and either confirm that it is not an issue here, or make some fix to solve it.\n\nAs far as I can tell, you did a little pattern matching like \"this new function looks similar to that previously removed function\" and assuming \"therefore it has the same bugs and limitations of the previous function.\" This is a reasonable assumption, but it happens not to be true in this case!\n\n[quoted text omitted]\nSorry yes I should have clarified I only think the pattern is good for external code that does not include source locations. Internal logs should definitely have source locations! I don't think you will find any regressions on that front either implemented in this PR or enabled by it.\n\nTo the contrary, followup PR #30343 **adds** source locations to wallet code which is currently missing them."
  },
  {
   "t": "2026-03-10T18:18:02Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "[quoted text omitted]\n\nOf course, this synthetic example is not found in the codebase as-is, but I don't see why it wouldn't compile with the changes in this pull\n\n```cpp\nstruct Module {\nstd::string m_name;\ntemplate<Level level>\nvoid ModuleLog(std::string m) { LogPrint((.level=level), \"[%s] %s\", m_name, m); }\n...\n};"
  },
  {
   "t": "2026-03-10T19:03:02Z",
   "kind": "review_comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "re: https://github.com/bitcoin/bitcoin/pull/34778#discussion_r2913611122\n\nThanks for the concrete example. I am assuming based on your earlier comments that problem with this example is that it hides source locations, and I agree hiding source locations would be bad. I guess I just disagree with the realism of the example. You seem to be saying is that this PR could make developers more tempted to write bad per-module logging interfaces and add calls like:\n\n```c++\nmy_module.ModuleLog<Level::Info>(\"message\")\n```\n\nto the code, hiding source locations that would otherwise be available. Even though developers could implement literally the same bad interface today by calling the LogInfo/LogWarning/LogError macros with an `if` or `switch` statement? And even though we already have an existing `WalletLogPrintf` function today which has no problem hiding source locations with the current logging macros?\n\nI just don't see this PR by itself having any real impact on support for source locations. But if that is the concern and I did not misunderstand something, thanks for clarifying."
  },
  {
   "t": "2026-03-16T14:53:23Z",
   "kind": "review_comment",
   "who": "maflcko",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "e983d97a9141180f9d06f510f17b87a3333b2954",
   "in_reply_to": 2912164572,
   "text": "[quoted text omitted]\n\nYou give a real place yourself (`WalletLogPrintf`), where a dev (or an LLM) could apply the example today (or use it as an excuse to introduce the pattern in another module) in any of the 300 open pulls.  So I don't see why the example should not be real.\n\n[quoted text omitted]\nFair enough, but at least this won't apply rate-limiting across levels, when it shouldn't.\n\nAnd to re-iterate an earlier point: Just as the logging was fixed to be consistent, so that one can call `git grep LogInfo` to find all info logs, this will introduce a new alias to grep for. I am sure over time devs will then use (inside the same file), stuff like:\n\n```\nLogPrint((.level = util::log::Level::Info), \"a\");\nLogInfo(\"b):\n```\n\nI don't see the point in allowing all of this, if there is no reason for it. Why not just indicate in the name of the macro or function that this is only meant for internal use, like it was before this pull request?"
  },
  {
   "t": "2026-04-01T17:37:20Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "fbc43e5b66a9e613499249b29bb6a74de5507c03"
  },
  {
   "t": "2026-04-03T11:57:18Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "31612a7f5f0d197bdc4a9747ad9e7509bf693d7d"
  },
  {
   "t": "2026-05-06T09:17:26Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "0c090593e8bdbdd3f65ea12aa1177ebc3d22d86a"
  },
  {
   "t": "2026-05-06T09:17:43Z",
   "kind": "comment",
   "who": "ryanofsky",
   "assoc": "MEMBER",
   "text": "Rebased 31612a7f5f0d197bdc4a9747ad9e7509bf693d7d -> 0c090593e8bdbdd3f65ea12aa1177ebc3d22d86a ([`pr/relog.3`](https://github.com/ryanofsky/bitcoin/commits/pr/relog.3) -> [`pr/relog.4`](https://github.com/ryanofsky/bitcoin/commits/pr/relog.4), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/relog.3-rebase..pr/relog.4)) due to conflict with #34865\n\nRebased 0c090593e8bdbdd3f65ea12aa1177ebc3d22d86a -> f0929e1b781af5012d835f78a8b54054fb5cb21e ([`pr/relog.4`](https://github.com/ryanofsky/bitcoin/commits/pr/relog.4) -> [`pr/relog.5`](https://github.com/ryanofsky/bitcoin/commits/pr/relog.5), [compare](https://github.com/ryanofsky/bitcoin/compare/pr/relog.4-rebase..pr/relog.5)) due to conflict with #34806"
  },
  {
   "t": "2026-05-26T20:14:42Z",
   "kind": "force_push",
   "who": "ryanofsky",
   "commit": "f0929e1b781af5012d835f78a8b54054fb5cb21e"
  },
  {
   "t": "2026-09-17T07:41:44Z",
   "kind": "comment",
   "who": "sedited",
   "assoc": "MEMBER",
   "text": "This has not received review for half a year, has a N-A-C-K and maflcko's last comment wasn't replied to. Maybe this should be closed at this point?"
  }
 ],
 "labels_log": [
  {
   "t": "2026-03-23T03:27:46Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-01T17:54:06Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-04-23T12:40:05Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-06T11:22:40Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-22T04:10:27Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-05-26T21:52:16Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2026-05-26T20:14:45Z",
   "kind": "renamed",
   "who": "ryanofsky",
   "from": "logging: rewrite macros to add ratelimit option, avoid unused strprintf, clarify confusing errors",
   "to": "logging: rewrite macros to enforce restrictions at compile-time, improve efficiency and usability"
  }
 ],
 "text_chars": 18631,
 "text_tokens_estimate": 4657,
 "changed_paths": [
  "doc/developer-notes.md",
  "src/logging.cpp",
  "src/logging.h",
  "src/test/logging_tests.cpp",
  "src/util/log.h",
  "src/validation.cpp"
 ],
 "files": [
  {
   "path": "doc/developer-notes.md",
   "add": 1,
   "del": 2
  },
  {
   "path": "src/logging.cpp",
   "add": 17,
   "del": 23
  },
  {
   "path": "src/logging.h",
   "add": 2,
   "del": 2
  },
  {
   "path": "src/test/logging_tests.cpp",
   "add": 116,
   "del": 21
  },
  {
   "path": "src/util/log.h",
   "add": 136,
   "del": 63
  },
  {
   "path": "src/validation.cpp",
   "add": 3,
   "del": 2
  }
 ],
 "test_lines": 137,
 "git": {
  "head": "f0929e1b781af5012d835f78a8b54054fb5cb21e",
  "head_matches_backup": true,
  "base": "a4157fc24a29118b1c9d1ac5b7977104217bcee9",
  "commits": [
   {
    "sha": "963ed23bc8",
    "subject": "log test: verify log argument evaluation semantics",
    "files": 1,
    "add": 26,
    "del": 0
   },
   {
    "sha": "3ea9b7cb10",
    "subject": "log test: add some test coverage on LogAcceptCategory",
    "files": 1,
    "add": 16,
    "del": 0
   },
   {
    "sha": "9c509ca53c",
    "subject": "log test: Add test for all accepted logging arguments",
    "files": 1,
    "add": 55,
    "del": 18
   },
   {
    "sha": "98f3bd6242",
    "subject": "log refactor: Ensure categories are not logged at info and higher levels",
    "files": 2,
    "add": 4,
    "del": 2
   },
   {
    "sha": "31f9929f3d",
    "subject": "log refactor: log macro rewrite",
    "files": 5,
    "add": 163,
    "del": 78
   },
   {
    "sha": "f0929e1b78",
    "subject": "log refactor: Drop Entry::should_ratelimit field",
    "files": 4,
    "add": 15,
    "del": 19
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "01b33155c591ee87",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}