upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.cpp')
-rw-r--r--src/util.cpp108
1 files changed, 103 insertions, 5 deletions
diff --git a/src/util.cpp b/src/util.cpp
index 7f56530..68bd18e 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -8,6 +8,99 @@
8 8
9bool fDebug = false; 9bool fDebug = false;
10 10
11// ---------------------------------------------------------------------------
12// Categorized, burst-collapsing logging -- see the LogPrint doc comment in
13// util.h for the problem this solves.
14// ---------------------------------------------------------------------------
15
16// Categories that explain the pool/worker/payout pipeline are on unconditionally:
17// silence there is exactly the "worker stuck, nothing then happens" complaint
18// this exists to fix, so it can't be opted out of by forgetting -debug.
19// "net" and "nostr" cover the per-address connection/discovery chatter that
20// used to dominate debug.log; they're gated behind fDebug like the printf()
21// calls they replace, so default output stays quiet unless requested.
22static bool LogCategoryDefaultOn(const char* category)
23{
24 return strcmp(category, "pool") == 0 ||
25 strcmp(category, "worker") == 0 ||
26 strcmp(category, "payout") == 0;
27}
28
29bool LogAcceptsCategory(const char* category)
30{
31 if (LogCategoryDefaultOn(category))
32 return true;
33 return fDebug;
34}
35
36// Only collapse bursts from the exact same call site within this window;
37// a different LogPrint() call (different file/line) is never merged with
38// this one, so unrelated messages never get mixed into one summary.
39static const int64 DEDUP_WINDOW_SECS = 3;
40
41struct LogDedupState {
42 int64 windowStart; // GetTime() when the current window opened
43 int suppressed; // calls swallowed so far this window
44 std::string lastMsg; // most recent message text, for the summary line
45};
46
47static std::map<std::string, LogDedupState> g_logDedup;
48static CCriticalSection cs_logDedup;
49
50void LogPrintDedup(const char* category, const char* file, int line, const std::string& msgIn)
51{
52 // Call sites follow the existing printf() convention of ending their
53 // format string with \n; strip it here so the single \n this function
54 // adds below doesn't turn into a blank line.
55 std::string msg = msgIn;
56 while (!msg.empty() && (msg.back() == '\n' || msg.back() == '\r'))
57 msg.pop_back();
58
59 char key[512];
60 my_snprintf(key, sizeof(key), "%s|%s:%d", category, file, line);
61
62 int64 now = GetTime();
63 bool fEmitNow = false;
64 int suppressedToFlush = 0;
65 std::string flushedMsg;
66
67 CRITICAL_BLOCK(cs_logDedup)
68 {
69 std::map<std::string, LogDedupState>::iterator it = g_logDedup.find(key);
70 if (it == g_logDedup.end())
71 {
72 // First time this call site has fired (or its last window is long
73 // gone) -- print it directly and open a fresh window.
74 g_logDedup[key] = LogDedupState{now, 0, msg};
75 fEmitNow = true;
76 }
77 else if (now - it->second.windowStart >= DEDUP_WINDOW_SECS)
78 {
79 // Window rolled over: flush what was suppressed during it (if
80 // anything), then start a new window with this call printed.
81 suppressedToFlush = it->second.suppressed;
82 flushedMsg = it->second.lastMsg;
83 it->second.windowStart = now;
84 it->second.suppressed = 0;
85 it->second.lastMsg = msg;
86 fEmitNow = true;
87 }
88 else
89 {
90 // Still inside the window and already printed one line for it:
91 // count this occurrence instead of writing another near-duplicate.
92 it->second.suppressed++;
93 it->second.lastMsg = msg;
94 }
95 }
96
97 if (suppressedToFlush > 0)
98 OutputDebugStringF("[%s] (%d similar in %llds, last: %s)\n",
99 category, suppressedToFlush, (long long)DEDUP_WINDOW_SECS, flushedMsg.c_str());
100 if (fEmitNow)
101 OutputDebugStringF("[%s] %s\n", category, msg.c_str());
102}
103
11 104
12 105
13 106
@@ -200,11 +293,16 @@ void PrintException(std::exception* pex, const char* pszThread)
200 snprintf(pszMessage, sizeof(pszMessage), 293 snprintf(pszMessage, sizeof(pszMessage),
201 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); 294 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
202 printf("\n\n************************\n%s", pszMessage); 295 printf("\n\n************************\n%s", pszMessage);
203 // Suppress the dialog and rethrow during shutdown — threads unwinding on 296 // Do NOT rethrow here. Every caller of PrintException (via
204 // exit cause spurious "UNKNOWN EXCEPTION" popups that aren't real errors. 297 // CATCH_PRINT_EXCEPTION) is a thread wrapped in its own
205 // Show error in GUI via repaint signal — GUI polls g_errorMessage 298 // "try { ThreadFoo2() } catch(...) { log, sleep, loop again }" self-healing
206 if (!fShutdown) 299 // retry loop -- that's the whole point of the wrapper. Rethrowing from
207 throw; 300 // inside that catch block escapes the retry loop entirely (nothing above
301 // it in the thread catches it) and takes down the whole process with
302 // std::terminate() on the very first transient error -- a flaky relay
303 // connection, a malformed message, anything -- instead of letting the
304 // thread log it, sleep 5s, and try again like it's designed to.
305 // Show error in GUI via repaint signal -- GUI polls g_errorMessage
208} 306}
209 307
210 308