Skip to content

Commit 0853d8d

Browse files
author
MarcoFalke
committed
Merge #16112: util: Log early messages
faa2a47 logging: Add threadsafety comments (MarcoFalke) 0b282f9 Log early messages with -printtoconsole (Anthony Towns) 4129874 Replace OpenDebugLog() with StartLogging() (Anthony Towns) Pull request description: Early log messages are dropped on the floor and they'd never make it to the console or debug log. This can be tested by running the test included in this pull request without re-compiling the `bitcoind`. Fix that by buffering early messages and flushing them as soon as all logging options have been initialized and logging has been started. This pull request is identical to "Log early messages with -printtoconsole" (#13088) by **ajtowns**, with the following changes: * Rebased * Added docstrings for `m_buffering` and `StartLogging` * Switch `CCriticalSection` (aka `RecursiveMutex`) to just `Mutex` in the last commit * Added tests Fixes #16098 Fixes #13157 Closes #13088 ACKs for commit faa2a4: ajtowns: utACK faa2a47 hebasto: ACK faa2a47 kristapsk: ACK faa2a47 (ran added functional test before / after recompiling, didn't do additional testing) Tree-SHA512: 685e2882642fe2a43ce171d42862582dadb840d03cda8236a994322c389ca2a1f3f431b179b2726c155c61793543bb340c568a5455d97f8b83bc7d307a85d387
2 parents 6c9d3c7 + faa2a47 commit 0853d8d

File tree

4 files changed

+63
-41
lines changed

4 files changed

+63
-41
lines changed

src/init.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -852,12 +852,6 @@ void InitLogging()
852852
{
853853
LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
854854
LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
855-
856-
// Add newlines to the logfile to distinguish this execution from the last
857-
// one; called before console logging is set up, so this is only sent to
858-
// debug.log.
859-
LogPrintf("\n\n\n\n\n");
860-
861855
LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
862856
LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
863857
LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
@@ -1237,10 +1231,10 @@ bool AppInitMain(InitInterfaces& interfaces)
12371231
// and because this needs to happen before any other debug.log printing
12381232
LogInstance().ShrinkDebugFile();
12391233
}
1240-
if (!LogInstance().OpenDebugLog()) {
1234+
}
1235+
if (!LogInstance().StartLogging()) {
12411236
return InitError(strprintf("Could not open debug log file %s",
12421237
LogInstance().m_file_path.string()));
1243-
}
12441238
}
12451239

12461240
if (!LogInstance().m_log_timestamps)

src/logging.cpp

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,38 @@ static int FileWriteStr(const std::string &str, FILE *fp)
3939
return fwrite(str.data(), 1, str.size(), fp);
4040
}
4141

42-
bool BCLog::Logger::OpenDebugLog()
42+
bool BCLog::Logger::StartLogging()
4343
{
44-
std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
44+
std::lock_guard<std::mutex> scoped_lock(m_cs);
4545

46+
assert(m_buffering);
4647
assert(m_fileout == nullptr);
47-
assert(!m_file_path.empty());
4848

49-
m_fileout = fsbridge::fopen(m_file_path, "a");
50-
if (!m_fileout) {
51-
return false;
49+
if (m_print_to_file) {
50+
assert(!m_file_path.empty());
51+
m_fileout = fsbridge::fopen(m_file_path, "a");
52+
if (!m_fileout) {
53+
return false;
54+
}
55+
56+
setbuf(m_fileout, nullptr); // unbuffered
57+
58+
// Add newlines to the logfile to distinguish this execution from the
59+
// last one.
60+
FileWriteStr("\n\n\n\n\n", m_fileout);
5261
}
5362

54-
setbuf(m_fileout, nullptr); // unbuffered
5563
// dump buffered messages from before we opened the log
64+
m_buffering = false;
5665
while (!m_msgs_before_open.empty()) {
57-
FileWriteStr(m_msgs_before_open.front(), m_fileout);
66+
const std::string& s = m_msgs_before_open.front();
67+
68+
if (m_print_to_file) FileWriteStr(s, m_fileout);
69+
if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
70+
5871
m_msgs_before_open.pop_front();
5972
}
73+
if (m_print_to_console) fflush(stdout);
6074

6175
return true;
6276
}
@@ -202,8 +216,9 @@ std::string BCLog::Logger::LogTimestampStr(const std::string& str)
202216
return strStamped;
203217
}
204218

205-
void BCLog::Logger::LogPrintStr(const std::string &str)
219+
void BCLog::Logger::LogPrintStr(const std::string& str)
206220
{
221+
std::lock_guard<std::mutex> scoped_lock(m_cs);
207222
std::string str_prefixed = str;
208223

209224
if (m_log_threadnames && m_started_new_line) {
@@ -214,32 +229,31 @@ void BCLog::Logger::LogPrintStr(const std::string &str)
214229

215230
m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
216231

232+
if (m_buffering) {
233+
// buffer if we haven't started logging yet
234+
m_msgs_before_open.push_back(str_prefixed);
235+
return;
236+
}
237+
217238
if (m_print_to_console) {
218239
// print to console
219240
fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
220241
fflush(stdout);
221242
}
222243
if (m_print_to_file) {
223-
std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
224-
225-
// buffer if we haven't opened the log yet
226-
if (m_fileout == nullptr) {
227-
m_msgs_before_open.push_back(str_prefixed);
228-
}
229-
else
230-
{
231-
// reopen the log file, if requested
232-
if (m_reopen_file) {
233-
m_reopen_file = false;
234-
FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
235-
if (new_fileout) {
236-
setbuf(new_fileout, nullptr); // unbuffered
237-
fclose(m_fileout);
238-
m_fileout = new_fileout;
239-
}
244+
assert(m_fileout != nullptr);
245+
246+
// reopen the log file, if requested
247+
if (m_reopen_file) {
248+
m_reopen_file = false;
249+
FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
250+
if (new_fileout) {
251+
setbuf(new_fileout, nullptr); // unbuffered
252+
fclose(m_fileout);
253+
m_fileout = new_fileout;
240254
}
241-
FileWriteStr(str_prefixed, m_fileout);
242255
}
256+
FileWriteStr(str_prefixed, m_fileout);
243257
}
244258
}
245259

src/logging.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ namespace BCLog {
6060
class Logger
6161
{
6262
private:
63-
FILE* m_fileout = nullptr;
64-
std::mutex m_file_mutex;
65-
std::list<std::string> m_msgs_before_open;
63+
mutable std::mutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected
64+
FILE* m_fileout = nullptr; // GUARDED_BY(m_cs)
65+
std::list<std::string> m_msgs_before_open; // GUARDED_BY(m_cs)
66+
bool m_buffering{true}; //!< Buffer messages before logging can be started. GUARDED_BY(m_cs)
6667

6768
/**
6869
* m_started_new_line is a state variable that will suppress printing of
@@ -88,12 +89,18 @@ namespace BCLog {
8889
std::atomic<bool> m_reopen_file{false};
8990

9091
/** Send a string to the log output */
91-
void LogPrintStr(const std::string &str);
92+
void LogPrintStr(const std::string& str);
9293

9394
/** Returns whether logs will be written to any output */
94-
bool Enabled() const { return m_print_to_console || m_print_to_file; }
95+
bool Enabled() const
96+
{
97+
std::lock_guard<std::mutex> scoped_lock(m_cs);
98+
return m_buffering || m_print_to_console || m_print_to_file;
99+
}
100+
101+
/** Start logging (and flush all buffered messages) */
102+
bool StartLogging();
95103

96-
bool OpenDebugLog();
97104
void ShrinkDebugFile();
98105

99106
uint32_t GetCategoryMask() const { return m_categories.load(); }

test/functional/feature_config_args.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,16 @@ def test_config_file_parser(self):
6161
with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf:
6262
conf.write('') # clear
6363

64+
def test_log_buffer(self):
65+
with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -connect=0']):
66+
self.start_node(0, extra_args=['-noconnect=0'])
67+
self.stop_node(0)
68+
6469
def run_test(self):
6570
self.stop_node(0)
6671

72+
self.test_log_buffer()
73+
6774
self.test_config_file_parser()
6875

6976
# Remove the -datadir argument so it doesn't override the config file

0 commit comments

Comments
 (0)