@@ -167,23 +167,51 @@ instance_of_cinit;
167
167
*/
168
168
169
169
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
170
+
170
171
/* *
171
- * We use boost::call_once() to make sure these are initialized
172
- * in a thread-safe manner the first time called:
172
+ * We use boost::call_once() to make sure mutexDebugLog and
173
+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
174
+ *
175
+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
176
+ * are leaked on exit. This is ugly, but will be cleaned up by
177
+ * the OS/libc. When the shutdown sequence is fully audited and
178
+ * tested, explicit destruction of these objects can be implemented.
173
179
*/
174
180
static FILE* fileout = NULL ;
175
181
static boost::mutex* mutexDebugLog = NULL ;
182
+ static list<string> *vMsgsBeforeOpenLog;
183
+
184
+ static int FileWriteStr (const std::string &str, FILE *fp)
185
+ {
186
+ return fwrite (str.data (), 1 , str.size (), fp);
187
+ }
176
188
177
189
static void DebugPrintInit ()
178
190
{
179
- assert (fileout == NULL );
180
191
assert (mutexDebugLog == NULL );
192
+ mutexDebugLog = new boost::mutex ();
193
+ vMsgsBeforeOpenLog = new list<string>;
194
+ }
195
+
196
+ void OpenDebugLog ()
197
+ {
198
+ boost::call_once (&DebugPrintInit, debugPrintInitFlag);
199
+ boost::mutex::scoped_lock scoped_lock (*mutexDebugLog);
181
200
201
+ assert (fileout == NULL );
202
+ assert (vMsgsBeforeOpenLog);
182
203
boost::filesystem::path pathDebug = GetDataDir () / " debug.log" ;
183
204
fileout = fopen (pathDebug.string ().c_str (), " a" );
184
205
if (fileout) setbuf (fileout, NULL ); // unbuffered
185
206
186
- mutexDebugLog = new boost::mutex ();
207
+ // dump buffered messages from before we opened the log
208
+ while (!vMsgsBeforeOpenLog->empty ()) {
209
+ FileWriteStr (vMsgsBeforeOpenLog->front (), fileout);
210
+ vMsgsBeforeOpenLog->pop_front ();
211
+ }
212
+
213
+ delete vMsgsBeforeOpenLog;
214
+ vMsgsBeforeOpenLog = NULL ;
187
215
}
188
216
189
217
bool LogAcceptCategory (const char * category)
@@ -215,44 +243,67 @@ bool LogAcceptCategory(const char* category)
215
243
return true ;
216
244
}
217
245
246
+ /* *
247
+ * fStartedNewLine is a state variable held by the calling context that will
248
+ * suppress printing of the timestamp when multiple calls are made that don't
249
+ * end in a newline. Initialize it to true, and hold it, in the calling context.
250
+ */
251
+ static std::string LogTimestampStr (const std::string &str, bool *fStartedNewLine )
252
+ {
253
+ string strStamped;
254
+
255
+ if (!fLogTimestamps )
256
+ return str;
257
+
258
+ if (*fStartedNewLine )
259
+ strStamped = DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , GetTime ()) + ' ' + str;
260
+ else
261
+ strStamped = str;
262
+
263
+ if (!str.empty () && str[str.size ()-1 ] == ' \n ' )
264
+ *fStartedNewLine = true ;
265
+ else
266
+ *fStartedNewLine = false ;
267
+
268
+ return strStamped;
269
+ }
270
+
218
271
int LogPrintStr (const std::string &str)
219
272
{
220
273
int ret = 0 ; // Returns total number of characters written
274
+ static bool fStartedNewLine = true ;
221
275
if (fPrintToConsole )
222
276
{
223
277
// print to console
224
278
ret = fwrite (str.data (), 1 , str.size (), stdout);
225
279
fflush (stdout);
226
280
}
227
- else if (fPrintToDebugLog && AreBaseParamsConfigured () )
281
+ else if (fPrintToDebugLog )
228
282
{
229
- static bool fStartedNewLine = true ;
230
283
boost::call_once (&DebugPrintInit, debugPrintInitFlag);
231
-
232
- if (fileout == NULL )
233
- return ret;
234
-
235
284
boost::mutex::scoped_lock scoped_lock (*mutexDebugLog);
236
285
237
- // reopen the log file, if requested
238
- if (fReopenDebugLog ) {
239
- fReopenDebugLog = false ;
240
- boost::filesystem::path pathDebug = GetDataDir () / " debug.log" ;
241
- if (freopen (pathDebug.string ().c_str ()," a" ,fileout) != NULL )
242
- setbuf (fileout, NULL ); // unbuffered
243
- }
286
+ string strTimestamped = LogTimestampStr (str, &fStartedNewLine );
244
287
245
- // Debug print useful for profiling
246
- if (fLogTimestamps && fStartedNewLine )
247
- ret += fprintf (fileout, " %s " , DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , GetTime ()).c_str ());
248
- if (!str.empty () && str[str.size ()-1 ] == ' \n ' )
249
- fStartedNewLine = true ;
288
+ // buffer if we haven't opened the log yet
289
+ if (fileout == NULL ) {
290
+ assert (vMsgsBeforeOpenLog);
291
+ ret = strTimestamped.length ();
292
+ vMsgsBeforeOpenLog->push_back (strTimestamped);
293
+ }
250
294
else
251
- fStartedNewLine = false ;
252
-
253
- ret = fwrite (str.data (), 1 , str.size (), fileout);
295
+ {
296
+ // reopen the log file, if requested
297
+ if (fReopenDebugLog ) {
298
+ fReopenDebugLog = false ;
299
+ boost::filesystem::path pathDebug = GetDataDir () / " debug.log" ;
300
+ if (freopen (pathDebug.string ().c_str ()," a" ,fileout) != NULL )
301
+ setbuf (fileout, NULL ); // unbuffered
302
+ }
303
+
304
+ ret = FileWriteStr (strTimestamped, fileout);
305
+ }
254
306
}
255
-
256
307
return ret;
257
308
}
258
309
0 commit comments