9797 #define LOG_TEE_TARGET stderr
9898#endif
9999
100- // NOTE: currently disabled as it produces too many log files
100+ // Utility for synchronizing log configuration state
101+ // since std::optional was introduced only in c++17
102+ enum LogTriState
103+ {
104+ LogTriStateSame,
105+ LogTriStateFalse,
106+ LogTriStateTrue
107+ };
108+
101109// Utility to obtain "pid" like unique process id and use it when creating log files.
102- // inline std::string log_get_pid()
103- // {
104- // static std::string pid;
105- // if (pid.empty())
106- // {
107- // // std::this_thread::get_id() is the most portable way of obtaining a "process id"
108- // // it's not the same as "pid" but is unique enough to solve multiple instances
109- // // trying to write to the same log.
110- // std::stringstream ss;
111- // ss << std::this_thread::get_id();
112- // pid = ss.str();
113- // }
114- //
115- // return pid;
116- // }
110+ inline std::string log_get_pid ()
111+ {
112+ static std::string pid;
113+ if (pid.empty ())
114+ {
115+ // std::this_thread::get_id() is the most portable way of obtaining a "process id"
116+ // it's not the same as "pid" but is unique enough to solve multiple instances
117+ // trying to write to the same log.
118+ std::stringstream ss;
119+ ss << std::this_thread::get_id ();
120+ pid = ss.str ();
121+ }
122+
123+ return pid;
124+ }
117125
118126// Utility function for generating log file names with unique id based on thread id.
119127// invocation with log_filename_generator( "llama", "log" ) creates a string "llama.<number>.log"
120128// where the number is a runtime id of the current thread.
121129
122- #define log_filename_generator (log_file_basename, log_file_extension ) log_filename_generator_impl(log_file_basename, log_file_extension)
130+ #define log_filename_generator (log_file_basename, log_file_extension ) log_filename_generator_impl(LogTriStateSame, log_file_basename, log_file_extension)
123131
124132// INTERNAL, DO NOT USE
125- inline std::string log_filename_generator_impl (const std::string & log_file_basename, const std::string & log_file_extension)
133+ inline std::string log_filename_generator_impl (LogTriState multilog, const std::string & log_file_basename, const std::string & log_file_extension)
126134{
135+ static bool _multilog = false ;
136+
137+ if (multilog != LogTriStateSame)
138+ {
139+ _multilog = multilog == LogTriStateTrue;
140+ }
141+
127142 std::stringstream buf;
128143
129144 buf << log_file_basename;
130- // buf << ".";
131- // buf << log_get_pid();
145+ if (_multilog)
146+ {
147+ buf << " ." ;
148+ buf << log_get_pid ();
149+ }
132150 buf << " ." ;
133151 buf << log_file_extension;
134152
@@ -213,15 +231,6 @@ inline std::string log_filename_generator_impl(const std::string & log_file_base
213231 #define LOG_TEE_FLF_VAL ," "
214232#endif
215233
216- // Utility for synchronizing log configuration state
217- // since std::optional was introduced only in c++17
218- enum LogTriState
219- {
220- LogTriStateSame,
221- LogTriStateFalse,
222- LogTriStateTrue
223- };
224-
225234// INTERNAL, DO NOT USE
226235// USE LOG() INSTEAD
227236//
@@ -315,16 +324,23 @@ enum LogTriState
315324#endif
316325
317326// INTERNAL, DO NOT USE
318- inline FILE *log_handler1_impl (bool change = false , LogTriState disable = LogTriStateSame, const std::string & filename = LOG_DEFAULT_FILE_NAME , FILE *target = nullptr )
327+ inline FILE *log_handler1_impl (bool change = false , LogTriState append = LogTriStateSame, LogTriState disable = LogTriStateSame, const std::string & filename = LOG_DEFAULT_FILE_NAME , FILE *target = nullptr )
319328{
320- static bool _initialized{false };
321- static bool _disabled{(filename.empty () && target == nullptr )};
329+ static bool _initialized = false ;
330+ static bool _append = false ;
331+ static bool _disabled = filename.empty () && target == nullptr ;
322332 static std::string log_current_filename{filename};
323333 static FILE *log_current_target{target};
324334 static FILE *logfile = nullptr ;
325335
326336 if (change)
327337 {
338+ if (append != LogTriStateSame)
339+ {
340+ _append = append == LogTriStateTrue;
341+ return logfile;
342+ }
343+
328344 if (disable == LogTriStateTrue)
329345 {
330346 // Disable primary target
@@ -377,7 +393,7 @@ inline FILE *log_handler1_impl(bool change = false, LogTriState disable = LogTri
377393 }
378394 }
379395
380- logfile = fopen (filename.c_str (), " w" );
396+ logfile = fopen (filename.c_str (), _append ? " a " : " w" );
381397 }
382398
383399 if (!logfile)
@@ -398,9 +414,9 @@ inline FILE *log_handler1_impl(bool change = false, LogTriState disable = LogTri
398414}
399415
400416// INTERNAL, DO NOT USE
401- inline FILE *log_handler2_impl (bool change = false , LogTriState disable = LogTriStateSame, FILE *target = nullptr , const std::string & filename = LOG_DEFAULT_FILE_NAME )
417+ inline FILE *log_handler2_impl (bool change = false , LogTriState append = LogTriStateSame, LogTriState disable = LogTriStateSame, FILE *target = nullptr , const std::string & filename = LOG_DEFAULT_FILE_NAME )
402418{
403- return log_handler1_impl (change, disable, filename, target);
419+ return log_handler1_impl (change, append, disable, filename, target);
404420}
405421
406422// Disables logs entirely at runtime.
@@ -411,7 +427,7 @@ inline FILE *log_handler2_impl(bool change = false, LogTriState disable = LogTri
411427// INTERNAL, DO NOT USE
412428inline FILE *log_disable_impl ()
413429{
414- return log_handler1_impl (true , LogTriStateTrue);
430+ return log_handler1_impl (true , LogTriStateSame, LogTriStateTrue);
415431}
416432
417433// Enables logs at runtime.
@@ -420,19 +436,31 @@ inline FILE *log_disable_impl()
420436// INTERNAL, DO NOT USE
421437inline FILE *log_enable_impl ()
422438{
423- return log_handler1_impl (true , LogTriStateFalse);
439+ return log_handler1_impl (true , LogTriStateSame, LogTriStateFalse);
424440}
425441
426442// Sets target fir logs, either by a file name or FILE* pointer (stdout, stderr, or any valid FILE*)
427443#define log_set_target (target ) log_set_target_impl(target)
428444
429445// INTERNAL, DO NOT USE
430- inline FILE *log_set_target_impl (const std::string & filename) { return log_handler1_impl (true , LogTriStateSame, filename); }
431- inline FILE *log_set_target_impl (FILE *target) { return log_handler2_impl (true , LogTriStateSame, target); }
446+ inline FILE *log_set_target_impl (const std::string & filename) { return log_handler1_impl (true , LogTriStateSame, LogTriStateSame, filename); }
447+ inline FILE *log_set_target_impl (FILE *target) { return log_handler2_impl (true , LogTriStateSame, LogTriStateSame, target); }
432448
433449// INTERNAL, DO NOT USE
434450inline FILE *log_handler () { return log_handler1_impl (); }
435451
452+ // Enable or disable creating separate log files for each run.
453+ // can ONLY be invoked BEFORE first log use.
454+ #define log_multilog (enable ) log_filename_generator_impl((enable) ? LogTriStateTrue : LogTriStateFalse, " " , " " )
455+ // Enable or disable append mode for log file.
456+ // can ONLY be invoked BEFORE first log use.
457+ #define log_append (enable ) log_append_impl(enable)
458+ // INTERNAL, DO NOT USE
459+ inline FILE *log_append_impl (bool enable)
460+ {
461+ return log_handler1_impl (true , enable ? LogTriStateTrue : LogTriStateFalse, LogTriStateSame);
462+ }
463+
436464inline void log_test ()
437465{
438466 log_disable ();
@@ -494,6 +522,18 @@ inline bool log_param_single_parse(const std::string & param)
494522 return true ;
495523 }
496524
525+ if (param == " --log-new" )
526+ {
527+ log_multilog (true );
528+ return true ;
529+ }
530+
531+ if (param == " --log-append" )
532+ {
533+ log_append (true );
534+ return true ;
535+ }
536+
497537 return false ;
498538}
499539
@@ -523,7 +563,9 @@ inline void log_print_usage()
523563 printf (" --log-disable Disable trace logs\n " );
524564 printf (" --log-enable Enable trace logs\n " );
525565 printf (" --log-file Specify a log filename (without extension)\n " );
526- printf (" Log file will be tagged with unique ID and written as \" <name>.<ID>.log\"\n " ); /* */
566+ printf (" --log-new Create a separate new log file on start. "
567+ " Each log file will have unique name: \" <name>.<ID>.log\"\n " );
568+ printf (" --log-append Don't truncate the old log file.\n " );
527569}
528570
529571#define log_dump_cmdline (argc, argv ) log_dump_cmdline_impl(argc, argv)
0 commit comments