3232
3333#include < time.h>
3434
35- #include < iostream >
35+ #include < sstream >
3636#include < string_view>
3737
3838enum LogLevel {
@@ -66,23 +66,32 @@ class Logger {
6666 Logger (LogLevel lvl) : m_LogLvl(lvl) {};
6767
6868 template <class ... ARGS>
69- void log (std::ostream& strm , LogLevel log_lvl,
70- const char *file, int line, ARGS&& ...args)
69+ void log (int fd , LogLevel log_lvl, const char *file ,
70+ int line, ARGS&& ...args)
7171 {
7272 if (!isLogPossible (log_lvl))
7373 return ;
74- time_t rawTime;
75- time (&rawTime);
76- struct tm *timeInfo = localtime (&rawTime);
77- char timeString[10 ];
78- strftime (timeString, sizeof (timeString), " %H:%M:%S" , timeInfo);
79- // The line below is commented for compatibility with previous
80- // version. I'm not sure it was bug or feature, but the time,
81- // filename and line was not printed.
74+ /* File and line were never printed (by mistake, I guess). */
8275 (void )file; (void )line;
83- // strm << timeString << " " << file << ':' << line << ' ';
76+ /*
77+ * Standard streams (`cout` and `cerr`) are thread-safe
78+ * according to C++11 or more modern standards, but it turns
79+ * out that some compilers do not stick to this contract.
80+ *
81+ * Let's use `stringstream` to build a string and then write
82+ * it manually with `write` since it is guaranteed to be
83+ * thread-safe. Yes, that's slower because of unnnecessary
84+ * allocations and copies, but the log is used generally for
85+ * debug or logging exceptional cases (errors) anyway, so
86+ * that's not a big deal.
87+ *
88+ * Related: https://github.com/llvm/llvm-project/issues/51851
89+ */
90+ std::stringstream strm;
8491 strm << log_lvl << " : " ;
8592 (strm << ... << std::forward<ARGS>(args)) << ' \n ' ;
93+ std::string str = strm.str ();
94+ (void )write (fd, std::data (str), std::size (str));
8695 }
8796 void setLogLevel (LogLevel lvl)
8897 {
@@ -106,7 +115,7 @@ template <class... ARGS>
106115void
107116log (LogLevel level, const char *file, int line, ARGS&& ...args)
108117{
109- gLogger .log (level == ERROR ? std::cerr : std::cout ,
118+ gLogger .log (level == ERROR ? STDERR_FILENO : STDOUT_FILENO ,
110119 level, file, line, std::forward<ARGS>(args)...);
111120}
112121
0 commit comments