upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 05:26:51 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 05:26:51 +0000
commitae1c6a7b49d9b4f8cf7218c0baec84f348eb5ef6 (patch)
treec8444d683f25d54135d5026eca4c677f24b7ab41
parente4f898c4a6b9900553c64b9804889b5fdae3e55f (diff)
log: cap debug.log in-process, and ship a logrotate policy
debug.log grew without bound (production: 1.95 GiB, 51-129 MB/day). Nothing shrank it once the process was up -- there is no ShrinkDebugFile in this tree, and upstream's only ran at startup. OutputDebugStringF now rolls the file to debug.log.old when it passes -maxdebugfilesize (MB, default 1024, 0 disables). The write path already opens and closes the file per line under one lock, so the rename-and-reopen is a few lines inside that lock and no fd can be stranded mid-roll. contrib/logrotate/bitflash-debug.logrotate is the longer-term policy (size 1G, rotate 4, compress, missingok, notifempty, copytruncate); copytruncate keeps the writer's append handle valid across rotation. Closes #34
-rw-r--r--src/main_gui.cpp15
-rw-r--r--src/util.cpp5
-rw-r--r--src/util.h29
3 files changed, 49 insertions, 0 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index 211e1e2..05f5ecf 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -111,6 +111,7 @@ static void PrintUsage()
111 printf(" /help, -help, --help, /?\n"); 111 printf(" /help, -help, --help, /?\n");
112 printf(" /datadir=PATH\n"); 112 printf(" /datadir=PATH\n");
113 printf(" /debug\n"); 113 printf(" /debug\n");
114 printf(" /maxdebugfilesize=N (roll debug.log at N MB, default 1024; 0 = never)\n");
114 printf(" /gen\n"); 115 printf(" /gen\n");
115 printf(" /nogui or /daemon\n"); 116 printf(" /nogui or /daemon\n");
116 printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n"); 117 printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n");
@@ -191,6 +192,20 @@ static void ParseStartupArguments(int argc, char* argv[])
191 if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) 192 if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug"))
192 fDebug = true; 193 fDebug = true;
193 194
195 // /maxdebugfilesize=N -- roll debug.log to debug.log.old once it passes
196 // N MB, checked on each write. Default is 1024 (see util.cpp); 0 turns
197 // the check off and leaves rotation entirely to logrotate.
198 string strMaxDebugSize = argval2(argc, argv, "/maxdebugfilesize", "-maxdebugfilesize");
199 if (!strMaxDebugSize.empty())
200 {
201 int64 nMB = atoi64(strMaxDebugSize.c_str());
202 if (nMB < 0)
203 fprintf(stderr, "Ignoring /maxdebugfilesize=%s: not a size in MB\n",
204 strMaxDebugSize.c_str());
205 else
206 nMaxDebugFileSize = nMB * 1024 * 1024;
207 }
208
194 if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen")) 209 if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen"))
195 { 210 {
196 fGenerateBitcoins = 1; 211 fGenerateBitcoins = 1;
diff --git a/src/util.cpp b/src/util.cpp
index 0cd0133..52cda84 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -8,6 +8,11 @@
8 8
9bool fDebug = false; 9bool fDebug = false;
10 10
11// In-process cap for debug.log, in bytes. Default matches the 1G trigger of
12// the shipped logrotate policy so a long-running node stays bounded even
13// without it; -maxdebugfilesize=N (MB) tunes it, 0 disables.
14int64 nMaxDebugFileSize = 1024 * 1024 * (int64)1024;
15
11// --------------------------------------------------------------------------- 16// ---------------------------------------------------------------------------
12// Categorized, burst-collapsing logging -- see the LogPrint doc comment in 17// Categorized, burst-collapsing logging -- see the LogPrint doc comment in
13// util.h for the problem this solves. 18// util.h for the problem this solves.
diff --git a/src/util.h b/src/util.h
index d72518b..f2ea23f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -87,6 +87,11 @@ inline T& REF(const T& val)
87 87
88extern bool fDebug; 88extern bool fDebug;
89 89
90// debug.log is rolled to debug.log.old once it grows past this many bytes
91// (set from -maxdebugfilesize, in MB; 0 disables the check). See the roll
92// site in OutputDebugStringF() below.
93extern int64 nMaxDebugFileSize;
94
90// --------------------------------------------------------------------------- 95// ---------------------------------------------------------------------------
91// Categorized, burst-collapsing logging 96// Categorized, burst-collapsing logging
92// 97//
@@ -391,6 +396,30 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
391 strDebugFile = "debug.log"; 396 strDebugFile = "debug.log";
392 } 397 }
393 FILE* fileout = fopen(strDebugFile.c_str(), "a"); 398 FILE* fileout = fopen(strDebugFile.c_str(), "a");
399 if (fileout && nMaxDebugFileSize > 0)
400 {
401 // Roll an overgrown debug.log before adding to it. Nothing in the
402 // tree shrinks this file once the process is running (there is no
403 // ShrinkDebugFile, and even Bitcoin's only ran at startup), so a
404 // node that stays up for months grows the log without bound --
405 // production hit ~2 GiB. The file is opened and closed per line,
406 // so a rename is safe here: the next line simply reopens the
407 // path. One generation is kept as debug.log.old; logrotate
408 // (contrib/logrotate/) handles anything longer-term.
409 int nSize = GetFilesize(fileout);
410 if (nSize >= 0 && (int64)nSize > nMaxDebugFileSize)
411 {
412 fclose(fileout);
413 string strOldFile = strDebugFile + ".old";
414 remove(strOldFile.c_str()); // rename() won't clobber on Windows
415 rename(strDebugFile.c_str(), strOldFile.c_str());
416 fileout = fopen(strDebugFile.c_str(), "a");
417 if (fileout)
418 fprintf(fileout,
419 "debug.log grew past %lld MB; previous contents moved to debug.log.old (-maxdebugfilesize)\n",
420 (long long)(nMaxDebugFileSize / 1024 / 1024));
421 }
422 }
394 if (fileout) 423 if (fileout)
395 { 424 {
396 va_list arg_ptr; 425 va_list arg_ptr;