@@ -175,23 +175,51 @@ instance_of_cinit;
175175 */
176176
177177static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT ;
178+
178179/* *
179- * We use boost::call_once() to make sure these are initialized
180- * in a thread-safe manner the first time called:
180+ * We use boost::call_once() to make sure mutexDebugLog and
181+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
182+ *
183+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
184+ * are leaked on exit. This is ugly, but will be cleaned up by
185+ * the OS/libc. When the shutdown sequence is fully audited and
186+ * tested, explicit destruction of these objects can be implemented.
181187 */
182188static FILE * fileout = NULL ;
183189static boost::mutex* mutexDebugLog = NULL ;
190+ static list<string> *vMsgsBeforeOpenLog;
191+
192+ static int FileWriteStr (const std::string &str, FILE *fp)
193+ {
194+ return fwrite (str.data (), 1 , str.size (), fp);
195+ }
184196
185197static void DebugPrintInit ()
186198{
187- assert (fileout == NULL );
188199 assert (mutexDebugLog == NULL );
200+ mutexDebugLog = new boost::mutex ();
201+ vMsgsBeforeOpenLog = new list<string>;
202+ }
203+
204+ void OpenDebugLog ()
205+ {
206+ boost::call_once (&DebugPrintInit, debugPrintInitFlag);
207+ boost::mutex::scoped_lock scoped_lock (*mutexDebugLog);
189208
209+ assert (fileout == NULL );
210+ assert (vMsgsBeforeOpenLog);
190211 boost::filesystem::path pathDebug = GetDataDir () / " debug.log" ;
191212 fileout = fopen (pathDebug.string ().c_str (), " a" );
192213 if (fileout) setbuf (fileout, NULL ); // unbuffered
193214
194- mutexDebugLog = new boost::mutex ();
215+ // dump buffered messages from before we opened the log
216+ while (!vMsgsBeforeOpenLog->empty ()) {
217+ FileWriteStr (vMsgsBeforeOpenLog->front (), fileout);
218+ vMsgsBeforeOpenLog->pop_front ();
219+ }
220+
221+ delete vMsgsBeforeOpenLog;
222+ vMsgsBeforeOpenLog = NULL ;
195223}
196224
197225bool LogAcceptCategory (const char * category)
@@ -223,44 +251,67 @@ bool LogAcceptCategory(const char* category)
223251 return true ;
224252}
225253
254+ /* *
255+ * fStartedNewLine is a state variable held by the calling context that will
256+ * suppress printing of the timestamp when multiple calls are made that don't
257+ * end in a newline. Initialize it to true, and hold it, in the calling context.
258+ */
259+ static std::string LogTimestampStr (const std::string &str, bool *fStartedNewLine )
260+ {
261+ string strStamped;
262+
263+ if (!fLogTimestamps )
264+ return str;
265+
266+ if (*fStartedNewLine )
267+ strStamped = DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , GetTime ()) + ' ' + str;
268+ else
269+ strStamped = str;
270+
271+ if (!str.empty () && str[str.size ()-1 ] == ' \n ' )
272+ *fStartedNewLine = true ;
273+ else
274+ *fStartedNewLine = false ;
275+
276+ return strStamped;
277+ }
278+
226279int LogPrintStr (const std::string &str)
227280{
228281 int ret = 0 ; // Returns total number of characters written
282+ static bool fStartedNewLine = true ;
229283 if (fPrintToConsole )
230284 {
231285 // print to console
232286 ret = fwrite (str.data (), 1 , str.size (), stdout);
233287 fflush (stdout);
234288 }
235- else if (fPrintToDebugLog && AreBaseParamsConfigured () )
289+ else if (fPrintToDebugLog )
236290 {
237- static bool fStartedNewLine = true ;
238291 boost::call_once (&DebugPrintInit, debugPrintInitFlag);
239-
240- if (fileout == NULL )
241- return ret;
242-
243292 boost::mutex::scoped_lock scoped_lock (*mutexDebugLog);
244293
245- // reopen the log file, if requested
246- if (fReopenDebugLog ) {
247- fReopenDebugLog = false ;
248- boost::filesystem::path pathDebug = GetDataDir () / " debug.log" ;
249- if (freopen (pathDebug.string ().c_str ()," a" ,fileout) != NULL )
250- setbuf (fileout, NULL ); // unbuffered
251- }
294+ string strTimestamped = LogTimestampStr (str, &fStartedNewLine );
252295
253- // Debug print useful for profiling
254- if (fLogTimestamps && fStartedNewLine )
255- ret += fprintf (fileout, " %s " , DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , GetTime ()).c_str ());
256- if (!str.empty () && str[str.size ()-1 ] == ' \n ' )
257- fStartedNewLine = true ;
296+ // buffer if we haven't opened the log yet
297+ if (fileout == NULL ) {
298+ assert (vMsgsBeforeOpenLog);
299+ ret = strTimestamped.length ();
300+ vMsgsBeforeOpenLog->push_back (strTimestamped);
301+ }
258302 else
259- fStartedNewLine = false ;
260-
261- ret = fwrite (str.data (), 1 , str.size (), fileout);
303+ {
304+ // reopen the log file, if requested
305+ if (fReopenDebugLog ) {
306+ fReopenDebugLog = false ;
307+ boost::filesystem::path pathDebug = GetDataDir () / " debug.log" ;
308+ if (freopen (pathDebug.string ().c_str ()," a" ,fileout) != NULL )
309+ setbuf (fileout, NULL ); // unbuffered
310+ }
311+
312+ ret = FileWriteStr (strTimestamped, fileout);
313+ }
262314 }
263-
264315 return ret;
265316}
266317
0 commit comments