diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc index 48a52f442..f0270df04 100644 --- a/src/libmain/progress-bar.cc +++ b/src/libmain/progress-bar.cc @@ -91,7 +91,7 @@ void ProgressBar::resume() nextWakeup = draw(*state, {}); state.wait_for(quitCV, std::chrono::milliseconds(50)); } - writeToStderr("\r\e[K"); + writeLogsToStderr("\r\e[K"); }); } @@ -124,7 +124,7 @@ void ProgressBar::log(State & state, Verbosity lvl, std::string_view s) } else { auto s2 = s + ANSI_NORMAL "\n"; if (!isTTY) s2 = filterANSIEscapes(s2, true); - writeToStderr(s2); + writeLogsToStderr(s2); } } @@ -322,9 +322,9 @@ void ProgressBar::eraseProgressDisplay(State & state) { if (printMultiline && (state.lastLines >= 1)) { // FIXME: make sure this works on windows - writeToStderr(fmt("\e[G\e[%dF\e[J", state.lastLines)); + writeLogsToStderr(fmt("\e[G\e[%dF\e[J", state.lastLines)); } else { - writeToStderr("\r\e[K"); + writeLogsToStderr("\r\e[K"); } } @@ -346,7 +346,7 @@ std::chrono::milliseconds ProgressBar::draw(State & state, const std::optional"; } - writeToStderr(prefix + filterANSIEscapes(s, !tty) + "\n"); + writeLogsToStderr(prefix + filterANSIEscapes(s, !tty) + "\n"); } void logEI(const ErrorInfo & ei) override @@ -117,8 +117,17 @@ Verbosity verbosityFromIntClamped(int val) return static_cast(clamped); } -void writeToStderr(std::string_view s) +void writeLogsToStderr(std::string_view s) { + static std::mutex lock; + + // make sure only one thread uses this function at any given time. + // multiple concurrent threads can have deleterious effects on log + // output, especially when layering structured formats (like JSON) + // on top of a SimpleLogger which is itself not thread-safe. every + // Logger instance should be thread-safe in an ideal world, but we + // cannot really enforce that on a per-logger level at this point. + std::unique_lock _lock(lock); try { writeFull(STDERR_FILENO, s, false); } catch (SysError & e) { diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 96f9f0782..b2d73d8ba 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -283,6 +283,6 @@ inline void warn(const std::string & fs, const Args & ... args) logger->warn(HintFmt(fs, args...).str()); } -void writeToStderr(std::string_view s); +void writeLogsToStderr(std::string_view s); }