diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-03 21:49:35 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-03 21:49:35 +0000 |
| commit | 3c18a66ef601d90f08ea622021cb02bafab1601b (patch) | |
| tree | ccb8ffec434c2c1eb9e0357c5692ee8aca42e159 /src | |
| parent | 4c6572f01d995e632338d7fb921962bb8f600eed (diff) | |
| parent | 74f1d8598a6f603fdfaf6c0487375c40166b76ec (diff) | |
merge: !2 fix/log-rotation into deploy/all-2026-08-24
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 6 | ||||
| -rw-r--r-- | src/main_gui.cpp | 50 | ||||
| -rw-r--r-- | src/net.h | 28 | ||||
| -rw-r--r-- | src/nostr.cpp | 2 | ||||
| -rw-r--r-- | src/util.cpp | 54 | ||||
| -rw-r--r-- | src/util.h | 69 |
6 files changed, 193 insertions, 16 deletions
diff --git a/src/main.cpp b/src/main.cpp index be4ab5e..981509c 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -1713,7 +1713,7 @@ void CWalletTx::RelayWalletTransaction(CTxDB& txdb) | |||
| 1713 | uint256 hash = GetHash(); | 1713 | uint256 hash = GetHash(); |
| 1714 | if (!txdb.ContainsTx(hash)) | 1714 | if (!txdb.ContainsTx(hash)) |
| 1715 | { | 1715 | { |
| 1716 | if (LogAcceptsCategory("net")) printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str()); | 1716 | if (LogAcceptsCategory("relay")) printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str()); |
| 1717 | RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this); | 1717 | RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this); |
| 1718 | } | 1718 | } |
| 1719 | } | 1719 | } |
| @@ -3264,7 +3264,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 3264 | vRecv >> *pblock; | 3264 | vRecv >> *pblock; |
| 3265 | 3265 | ||
| 3266 | //// debug print | 3266 | //// debug print |
| 3267 | if (LogAcceptsCategory("net")) { printf("received block:\n"); pblock->print(); } | 3267 | if (LogAcceptsCategory("relay")) { printf("received block:\n"); pblock->print(); } |
| 3268 | 3268 | ||
| 3269 | CInv inv(MSG_BLOCK, pblock->GetHash()); | 3269 | CInv inv(MSG_BLOCK, pblock->GetHash()); |
| 3270 | pfrom->AddInventoryKnown(inv); | 3270 | pfrom->AddInventoryKnown(inv); |
| @@ -4643,7 +4643,7 @@ bool BitcoinMiner(int nThreadId) | |||
| 4643 | //// debug print | 4643 | //// debug print |
| 4644 | if (LogAcceptsCategory("net")) printf("BitcoinMiner:\n"); | 4644 | if (LogAcceptsCategory("net")) printf("BitcoinMiner:\n"); |
| 4645 | if (LogAcceptsCategory("net")) printf("RandomX proof-of-work found \n powhash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); | 4645 | if (LogAcceptsCategory("net")) printf("RandomX proof-of-work found \n powhash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); |
| 4646 | if (LogAcceptsCategory("net")) pblock->print(); | 4646 | if (LogAcceptsCategory("relay")) pblock->print(); |
| 4647 | 4647 | ||
| 4648 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); | 4648 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); |
| 4649 | CRITICAL_BLOCK(cs_main) | 4649 | CRITICAL_BLOCK(cs_main) |
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 211e1e2..0e64985 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -111,6 +111,8 @@ 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(" /debugrelay (/debug plus per-message relay chatter and block dumps)\n"); | ||
| 115 | printf(" /maxdebugfilesize=N (roll debug.log at N MB, default 1024; 0 = never)\n"); | ||
| 114 | printf(" /gen\n"); | 116 | printf(" /gen\n"); |
| 115 | printf(" /nogui or /daemon\n"); | 117 | printf(" /nogui or /daemon\n"); |
| 116 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n"); | 118 | printf(" /selftest=wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt,\n"); |
| @@ -191,6 +193,54 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 191 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) | 193 | if (arg(argc,argv,"/debug") || arg(argc,argv,"-debug")) |
| 192 | fDebug = true; | 194 | fDebug = true; |
| 193 | 195 | ||
| 196 | // /debugrelay -- everything /debug shows, plus the per-message firehose | ||
| 197 | // ("relay" and "nostrdiscovery" categories: sending: tx, Relaying wtx, | ||
| 198 | // raw CBlock dumps, per-peer discovery lines). That traffic was ~90% of | ||
| 199 | // a 13-hour production debug.log (issue #35), so plain /debug leaves it | ||
| 200 | // off; the message text itself is unchanged for anyone grepping it. | ||
| 201 | if (arg(argc,argv,"/debugrelay") || arg(argc,argv,"-debugrelay")) | ||
| 202 | { | ||
| 203 | fDebug = true; | ||
| 204 | fDebugRelay = true; | ||
| 205 | } | ||
| 206 | |||
| 207 | // /maxdebugfilesize=N -- roll debug.log to debug.log.old once it passes | ||
| 208 | // N MB, checked on each write. Default is 1024 (see util.cpp); 0 turns | ||
| 209 | // the check off and leaves rotation entirely to logrotate. | ||
| 210 | string strMaxDebugSize = argval2(argc, argv, "/maxdebugfilesize", "-maxdebugfilesize"); | ||
| 211 | if (!strMaxDebugSize.empty()) | ||
| 212 | { | ||
| 213 | // Parsed with atoi64() before, which is strtoll() with the endptr | ||
| 214 | // thrown away: it returns 0 for anything it cannot read, so | ||
| 215 | // /maxdebugfilesize=1G and =1024MB both came out as 0 -- "never | ||
| 216 | // roll", identical to asking for that on purpose, with nothing said | ||
| 217 | // to the operator. The old code also multiplied without a range | ||
| 218 | // check, so a big enough N wrapped to a negative cap, which the roll | ||
| 219 | // reads as "off" too. Every rejection is now reported and leaves the | ||
| 220 | // default in place; the value is a plain count of MB, no suffix. | ||
| 221 | const char* psz = strMaxDebugSize.c_str(); | ||
| 222 | char* pszEnd = NULL; | ||
| 223 | errno = 0; | ||
| 224 | int64 nMB = strtoll(psz, &pszEnd, 10); | ||
| 225 | // INT64_MAX, without depending on which limits header this tree pulls in. | ||
| 226 | const int64 nMaxMB = (int64)((~(uint64)0) >> 1) / (1024 * 1024); | ||
| 227 | const char* pszWhy = NULL; | ||
| 228 | if (pszEnd == psz) | ||
| 229 | pszWhy = "not a number"; | ||
| 230 | else if (*pszEnd != '\0') | ||
| 231 | pszWhy = "trailing characters -- the value is a count of MB, with no unit suffix"; | ||
| 232 | else if (errno == ERANGE || nMB < 0) | ||
| 233 | pszWhy = "not a size in MB"; | ||
| 234 | else if (nMB > nMaxMB) | ||
| 235 | pszWhy = "larger than a file size can be"; | ||
| 236 | if (pszWhy) | ||
| 237 | fprintf(stderr, "Ignoring /maxdebugfilesize=%s: %s (keeping %lld MB)\n", | ||
| 238 | strMaxDebugSize.c_str(), pszWhy, | ||
| 239 | (long long)(nMaxDebugFileSize / 1024 / 1024)); | ||
| 240 | else | ||
| 241 | nMaxDebugFileSize = nMB * 1024 * 1024; | ||
| 242 | } | ||
| 243 | |||
| 194 | if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen")) | 244 | if (arg(argc,argv,"/gen") || arg(argc,argv,"-gen")) |
| 195 | { | 245 | { |
| 196 | fGenerateBitcoins = 1; | 246 | fGenerateBitcoins = 1; |
| @@ -802,6 +802,18 @@ public: | |||
| 802 | 802 | ||
| 803 | 803 | ||
| 804 | 804 | ||
| 805 | // "sending: tx (N bytes)" alone was ~71% of a 13-hour production | ||
| 806 | // debug.log (issue #35), so tx sends are demoted to the /debugrelay-gated | ||
| 807 | // "relay" category; every other command's send trace stays on "net". | ||
| 808 | // The line is emitted in pieces across BeginMessage/EndMessage/ | ||
| 809 | // AbortMessage, so all three must agree on the category or orphaned | ||
| 810 | // "(N bytes)" fragments would leak into a plain -debug log. | ||
| 811 | // Valid only mid-message (nPushPos != -1). | ||
| 812 | const char* SendLogCategory() const | ||
| 813 | { | ||
| 814 | return strcmp(GetMessageCommand(), "tx") == 0 ? "relay" : "net"; | ||
| 815 | } | ||
| 816 | |||
| 805 | void BeginMessage(const char* pszCommand) | 817 | void BeginMessage(const char* pszCommand) |
| 806 | { | 818 | { |
| 807 | EnterCriticalSection(&cs_vSend); | 819 | EnterCriticalSection(&cs_vSend); |
| @@ -809,17 +821,19 @@ public: | |||
| 809 | AbortMessage(); | 821 | AbortMessage(); |
| 810 | nPushPos = vSend.size(); | 822 | nPushPos = vSend.size(); |
| 811 | vSend << CMessageHeader(pszCommand, 0); | 823 | vSend << CMessageHeader(pszCommand, 0); |
| 812 | if (LogAcceptsCategory("net")) printf("sending: %-12s ", pszCommand); | 824 | if (LogAcceptsCategory(SendLogCategory())) printf("sending: %-12s ", pszCommand); |
| 813 | } | 825 | } |
| 814 | 826 | ||
| 815 | void AbortMessage() | 827 | void AbortMessage() |
| 816 | { | 828 | { |
| 817 | if (nPushPos == -1) | 829 | if (nPushPos == -1) |
| 818 | return; | 830 | return; |
| 831 | // Capture before nPushPos is cleared; GetMessageCommand() needs it. | ||
| 832 | const char* pszCategory = SendLogCategory(); | ||
| 819 | vSend.resize(nPushPos); | 833 | vSend.resize(nPushPos); |
| 820 | nPushPos = -1; | 834 | nPushPos = -1; |
| 821 | LeaveCriticalSection(&cs_vSend); | 835 | LeaveCriticalSection(&cs_vSend); |
| 822 | if (LogAcceptsCategory("net")) printf("(aborted)\n"); | 836 | if (LogAcceptsCategory(pszCategory)) printf("(aborted)\n"); |
| 823 | } | 837 | } |
| 824 | 838 | ||
| 825 | void EndMessage() | 839 | void EndMessage() |
| @@ -827,7 +841,11 @@ public: | |||
| 827 | extern int nDropMessagesTest; | 841 | extern int nDropMessagesTest; |
| 828 | if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) | 842 | if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) |
| 829 | { | 843 | { |
| 830 | if (LogAcceptsCategory("net")) printf("dropmessages DROPPING SEND MESSAGE\n"); | 844 | // Same category as the "sending: " this line interrupts, so a tx |
| 845 | // does not announce its own drop under "net" having been gated | ||
| 846 | // off under "relay". nPushPos can be -1 here, and then | ||
| 847 | // GetMessageCommand() returns "" and this is "net" as before. | ||
| 848 | if (LogAcceptsCategory(SendLogCategory())) printf("dropmessages DROPPING SEND MESSAGE\n"); | ||
| 831 | AbortMessage(); | 849 | AbortMessage(); |
| 832 | return; | 850 | return; |
| 833 | } | 851 | } |
| @@ -839,10 +857,10 @@ public: | |||
| 839 | unsigned int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader); | 857 | unsigned int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader); |
| 840 | memcpy((char*)&vSend[nPushPos] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); | 858 | memcpy((char*)&vSend[nPushPos] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); |
| 841 | 859 | ||
| 842 | if (LogAcceptsCategory("net")) printf("(%d bytes) ", nSize); | 860 | if (LogAcceptsCategory(SendLogCategory())) printf("(%d bytes) ", nSize); |
| 843 | //for (int i = nPushPos+sizeof(CMessageHeader); i < min(vSend.size(), nPushPos+sizeof(CMessageHeader)+20U); i++) | 861 | //for (int i = nPushPos+sizeof(CMessageHeader); i < min(vSend.size(), nPushPos+sizeof(CMessageHeader)+20U); i++) |
| 844 | // printf("%02x ", vSend[i] & 0xff); | 862 | // printf("%02x ", vSend[i] & 0xff); |
| 845 | if (LogAcceptsCategory("net")) printf("\n"); | 863 | if (LogAcceptsCategory(SendLogCategory())) printf("\n"); |
| 846 | 864 | ||
| 847 | nPushPos = -1; | 865 | nPushPos = -1; |
| 848 | LeaveCriticalSection(&cs_vSend); | 866 | LeaveCriticalSection(&cs_vSend); |
diff --git a/src/nostr.cpp b/src/nostr.cpp index 0717e12..f44dc08 100644 --- a/src/nostr.cpp +++ b/src/nostr.cpp | |||
| @@ -1465,7 +1465,7 @@ static bool SeedFromRelay(CNostrKey& key, const string& relay) | |||
| 1465 | else if (createdAt > it->second) it->second = createdAt; // refresh | 1465 | else if (createdAt > it->second) it->second = createdAt; // refresh |
| 1466 | } | 1466 | } |
| 1467 | if (fNew && fDebug) | 1467 | if (fNew && fDebug) |
| 1468 | LogPrint("nostr", "Nostr: discovered .btf peer %s\n", peerAddr.c_str()); | 1468 | LogPrint("nostrdiscovery", "Nostr: discovered .btf peer %s\n", peerAddr.c_str()); |
| 1469 | if (++nPeers > 500) break; | 1469 | if (++nPeers > 500) break; |
| 1470 | } | 1470 | } |
| 1471 | else if (type == "EOSE") | 1471 | else if (type == "EOSE") |
diff --git a/src/util.cpp b/src/util.cpp index 0cd0133..60142be 100644 --- a/src/util.cpp +++ b/src/util.cpp | |||
| @@ -7,6 +7,12 @@ | |||
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | bool fDebug = false; | 9 | bool fDebug = false; |
| 10 | bool fDebugRelay = false; | ||
| 11 | |||
| 12 | // In-process cap for debug.log, in bytes. Default matches the 1G trigger of | ||
| 13 | // the shipped logrotate policy so a long-running node stays bounded even | ||
| 14 | // without it; -maxdebugfilesize=N (MB) tunes it, 0 disables. | ||
| 15 | int64 nMaxDebugFileSize = 1024 * 1024 * (int64)1024; | ||
| 10 | 16 | ||
| 11 | // --------------------------------------------------------------------------- | 17 | // --------------------------------------------------------------------------- |
| 12 | // Categorized, burst-collapsing logging -- see the LogPrint doc comment in | 18 | // Categorized, burst-collapsing logging -- see the LogPrint doc comment in |
| @@ -26,10 +32,22 @@ static bool LogCategoryDefaultOn(const char* category) | |||
| 26 | strcmp(category, "payout") == 0; | 32 | strcmp(category, "payout") == 0; |
| 27 | } | 33 | } |
| 28 | 34 | ||
| 35 | // Categories so noisy they drown out everything else even under -debug: | ||
| 36 | // per-message send traces, wallet relay rebroadcasts, raw CBlock dumps and | ||
| 37 | // per-address discovery lines made up ~90% of a 13-hour production capture | ||
| 38 | // (issue #35). They need /debugrelay, not merely /debug. | ||
| 39 | static bool LogCategoryVerboseOnly(const char* category) | ||
| 40 | { | ||
| 41 | return strcmp(category, "relay") == 0 || | ||
| 42 | strcmp(category, "nostrdiscovery") == 0; | ||
| 43 | } | ||
| 44 | |||
| 29 | bool LogAcceptsCategory(const char* category) | 45 | bool LogAcceptsCategory(const char* category) |
| 30 | { | 46 | { |
| 31 | if (LogCategoryDefaultOn(category)) | 47 | if (LogCategoryDefaultOn(category)) |
| 32 | return true; | 48 | return true; |
| 49 | if (LogCategoryVerboseOnly(category)) | ||
| 50 | return fDebugRelay; | ||
| 33 | return fDebug; | 51 | return fDebug; |
| 34 | } | 52 | } |
| 35 | 53 | ||
| @@ -397,13 +415,37 @@ bool FileExists(const char* psz) | |||
| 397 | #endif | 415 | #endif |
| 398 | } | 416 | } |
| 399 | 417 | ||
| 400 | int GetFilesize(FILE* file) | 418 | #ifndef _WIN32 |
| 419 | // If off_t is 32 bits wide, ftello() truncates exactly like the int this | ||
| 420 | // function used to return. Fail the build rather than ship the silent | ||
| 421 | // version of the bug (32-bit hosts need -D_FILE_OFFSET_BITS=64). | ||
| 422 | static_assert(sizeof(off_t) >= 8, "GetFilesize needs a 64-bit off_t"); | ||
| 423 | #endif | ||
| 424 | |||
| 425 | // Returns the file's size in bytes, or -1 if it cannot be determined. | ||
| 426 | // | ||
| 427 | // This used to hold ftell()'s long in an int, so a file of 2 GiB or more came | ||
| 428 | // back negative. Its only caller is the debug.log roll in util.h, which skips | ||
| 429 | // the roll on a negative size -- i.e. rotation switched itself off for good at | ||
| 430 | // exactly the size the roll exists to prevent, and any cap of 2048 MB or more | ||
| 431 | // could never be exceeded at all. Both failures were silent. | ||
| 432 | int64 GetFilesize(FILE* file) | ||
| 401 | { | 433 | { |
| 402 | int nSavePos = ftell(file); | 434 | #ifdef _WIN32 |
| 403 | int nFilesize = -1; | 435 | __int64 nSavePos = _ftelli64(file); |
| 404 | if (fseek(file, 0, SEEK_END) == 0) | 436 | int64 nFilesize = -1; |
| 405 | nFilesize = ftell(file); | 437 | if (nSavePos >= 0 && _fseeki64(file, 0, SEEK_END) == 0) |
| 406 | fseek(file, nSavePos, SEEK_SET); | 438 | nFilesize = _ftelli64(file); |
| 439 | if (nSavePos >= 0) | ||
| 440 | _fseeki64(file, nSavePos, SEEK_SET); | ||
| 441 | #else | ||
| 442 | off_t nSavePos = ftello(file); | ||
| 443 | int64 nFilesize = -1; | ||
| 444 | if (nSavePos >= 0 && fseeko(file, 0, SEEK_END) == 0) | ||
| 445 | nFilesize = ftello(file); | ||
| 446 | if (nSavePos >= 0) | ||
| 447 | fseeko(file, nSavePos, SEEK_SET); | ||
| 448 | #endif | ||
| 407 | return nFilesize; | 449 | return nFilesize; |
| 408 | } | 450 | } |
| 409 | 451 | ||
| @@ -87,6 +87,15 @@ inline T& REF(const T& val) | |||
| 87 | 87 | ||
| 88 | extern bool fDebug; | 88 | extern bool fDebug; |
| 89 | 89 | ||
| 90 | // /debugrelay: the per-message firehose ("relay" and "nostrdiscovery" | ||
| 91 | // categories) that even -debug keeps off. See LogAcceptsCategory(). | ||
| 92 | extern bool fDebugRelay; | ||
| 93 | |||
| 94 | // debug.log is rolled to debug.log.old once it grows past this many bytes | ||
| 95 | // (set from -maxdebugfilesize, in MB; 0 disables the check). See the roll | ||
| 96 | // site in OutputDebugStringF() below. | ||
| 97 | extern int64 nMaxDebugFileSize; | ||
| 98 | |||
| 90 | // --------------------------------------------------------------------------- | 99 | // --------------------------------------------------------------------------- |
| 91 | // Categorized, burst-collapsing logging | 100 | // Categorized, burst-collapsing logging |
| 92 | // | 101 | // |
| @@ -145,7 +154,7 @@ void ParseString(const string& str, char c, vector<string>& v); | |||
| 145 | string FormatMoney(int64 n, bool fPlus=false); | 154 | string FormatMoney(int64 n, bool fPlus=false); |
| 146 | bool ParseMoney(const char* pszIn, int64& nRet); | 155 | bool ParseMoney(const char* pszIn, int64& nRet); |
| 147 | bool FileExists(const char* psz); | 156 | bool FileExists(const char* psz); |
| 148 | int GetFilesize(FILE* file); | 157 | int64 GetFilesize(FILE* file); |
| 149 | uint64 GetRand(uint64 nMax); | 158 | uint64 GetRand(uint64 nMax); |
| 150 | int64 GetTime(); | 159 | int64 GetTime(); |
| 151 | int64 GetAdjustedTime(); | 160 | int64 GetAdjustedTime(); |
| @@ -390,7 +399,65 @@ inline int OutputDebugStringF(const char* pszFormat, ...) | |||
| 390 | else | 399 | else |
| 391 | strDebugFile = "debug.log"; | 400 | strDebugFile = "debug.log"; |
| 392 | } | 401 | } |
| 402 | // Latched by a failed rename in the roll below, which cannot be | ||
| 403 | // retried usefully and must not be retried endlessly. | ||
| 404 | static bool fRollDisabled = false; | ||
| 393 | FILE* fileout = fopen(strDebugFile.c_str(), "a"); | 405 | FILE* fileout = fopen(strDebugFile.c_str(), "a"); |
| 406 | if (fileout && nMaxDebugFileSize > 0 && !fRollDisabled) | ||
| 407 | { | ||
| 408 | // Roll an overgrown debug.log before adding to it. Nothing in the | ||
| 409 | // tree shrinks this file once the process is running (there is no | ||
| 410 | // ShrinkDebugFile, and even Bitcoin's only ran at startup), so a | ||
| 411 | // node that stays up for months grows the log without bound -- | ||
| 412 | // production hit ~2 GiB. The file is opened and closed per line, | ||
| 413 | // so a rename is safe here: the next line simply reopens the | ||
| 414 | // path. One generation is kept as debug.log.old; logrotate | ||
| 415 | // (contrib/logrotate/) handles anything longer-term. | ||
| 416 | int64 nSize = GetFilesize(fileout); | ||
| 417 | if (nSize >= 0 && nSize > nMaxDebugFileSize) | ||
| 418 | { | ||
| 419 | fclose(fileout); | ||
| 420 | string strOldFile = strDebugFile + ".old"; | ||
| 421 | remove(strOldFile.c_str()); // rename() won't clobber on Windows | ||
| 422 | bool fRolled = (rename(strDebugFile.c_str(), strOldFile.c_str()) == 0); | ||
| 423 | int nRenameErrno = errno; // before fopen() can overwrite it | ||
| 424 | fileout = fopen(strDebugFile.c_str(), "a"); | ||
| 425 | if (fRolled) | ||
| 426 | { | ||
| 427 | if (fileout) | ||
| 428 | fprintf(fileout, | ||
| 429 | "debug.log grew past %lld MB; previous contents moved to debug.log.old (-maxdebugfilesize)\n", | ||
| 430 | (long long)(nMaxDebugFileSize / 1024 / 1024)); | ||
| 431 | } | ||
| 432 | else if (nRenameErrno == ENOENT) | ||
| 433 | { | ||
| 434 | // The file went away between the size check and the | ||
| 435 | // rename, so an external rotator (logrotate) got there | ||
| 436 | // first. Nothing left to roll and nothing wrong: the | ||
| 437 | // fopen above has already recreated it. Latching on this | ||
| 438 | // would let a benign race with logrotate switch the cap | ||
| 439 | // off for the rest of the run. | ||
| 440 | } | ||
| 441 | else | ||
| 442 | { | ||
| 443 | // The file is still over the cap, so this branch would be | ||
| 444 | // reached again on the next line and every line after it. | ||
| 445 | // Unlatched, the complaint about failing to roll becomes | ||
| 446 | // the runaway growth the roll exists to prevent. Say it | ||
| 447 | // once and stop trying -- on stderr too, because whatever | ||
| 448 | // blocked the rename (read-only mount, permissions, EXDEV | ||
| 449 | // across a bind mount) may equally block the log write. | ||
| 450 | fRollDisabled = true; | ||
| 451 | fprintf(stderr, | ||
| 452 | "cannot roll %s (rename to .old failed: %s); -maxdebugfilesize disabled for this run\n", | ||
| 453 | strDebugFile.c_str(), strerror(nRenameErrno)); | ||
| 454 | if (fileout) | ||
| 455 | fprintf(fileout, | ||
| 456 | "cannot roll debug.log (rename to .old failed: %s); -maxdebugfilesize disabled for this run\n", | ||
| 457 | strerror(nRenameErrno)); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | } | ||
| 394 | if (fileout) | 461 | if (fileout) |
| 395 | { | 462 | { |
| 396 | va_list arg_ptr; | 463 | va_list arg_ptr; |