diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index e48f8272..50d8516e 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef _WIN32 @@ -474,6 +475,19 @@ inline bool in_terminal(FILE *file) return isatty(fileno(file)) != 0; #endif } + +// stdout/stderr global mutexes +inline std::mutex& stdout_mutex() +{ + static std::mutex &mutex = std::mutex{}; + return mutex; +} + +inline std::mutex& stderr_mutex() +{ + static std::mutex &mutex = std::mutex{}; + return mutex; +} } // namespace os } // namespace details } // namespace spdlog diff --git a/include/spdlog/sinks/wincolor_sink.h b/include/spdlog/sinks/wincolor_sink.h index 402fa121..c44c0023 100644 --- a/include/spdlog/sinks/wincolor_sink.h +++ b/include/spdlog/sinks/wincolor_sink.h @@ -10,6 +10,7 @@ #include "base_sink.h" #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace sinks { * Windows color console sink. Uses WriteConsoleA to write to the console with colors */ template -class wincolor_sink : public base_sink +class wincolor_sink : public sink { public: const WORD BOLD = FOREGROUND_INTENSITY; @@ -30,8 +31,8 @@ public: const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; - wincolor_sink(HANDLE std_handle) - : out_handle_(std_handle) + wincolor_sink(HANDLE std_handle, Mutex& stdout_mutex) + : out_handle_(std_handle), _mutex(stdout_mutex) { colors_[level::trace] = WHITE; colors_[level::debug] = CYAN; @@ -42,6 +43,7 @@ public: colors_[level::off] = 0; } + ~wincolor_sink() override { this->flush(); @@ -57,55 +59,58 @@ public: colors_[level] = color; } -protected: - void _sink_it(const details::log_msg &msg) override - { - if (msg.color_range_end > msg.color_range_start) - { - // before color range - _print_range(msg, 0, msg.color_range_start); + void log(const details::log_msg &msg) SPDLOG_FINAL override + { + std::lock_guard lock(_mutex); - // in color range - auto orig_attribs = set_console_attribs(colors_[msg.level]); - _print_range(msg, msg.color_range_start, msg.color_range_end); - ::SetConsoleTextAttribute(out_handle_, orig_attribs); // reset to orig colors - // after color range - _print_range(msg, msg.color_range_end, msg.formatted.size()); - } - else // print without colors if color range is invalid - { - _print_range(msg, 0, msg.formatted.size()); - } - } + if (msg.color_range_end > msg.color_range_start) + { + // before color range + _print_range(msg, 0, msg.color_range_start); - void _flush() override - { - // windows console always flushed? - } + // in color range + auto orig_attribs = set_console_attribs(colors_[msg.level]); + _print_range(msg, msg.color_range_start, msg.color_range_end); + ::SetConsoleTextAttribute(out_handle_, orig_attribs); // reset to orig colors + // after color range + _print_range(msg, msg.color_range_end, msg.formatted.size()); + } + else // print without colors if color range is invalid + { + _print_range(msg, 0, msg.formatted.size()); + } + } -private: - HANDLE out_handle_; - std::unordered_map colors_; + void flush() SPDLOG_FINAL override + { + // windows console always flushed? + } + +private: // set color and return the orig console attributes (for resetting later) WORD set_console_attribs(WORD attribs) { CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; - GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); + ::GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); WORD back_color = orig_buffer_info.wAttributes; // retrieve the current background color back_color &= static_cast(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)); // keep the background color unchanged - SetConsoleTextAttribute(out_handle_, attribs | back_color); + ::SetConsoleTextAttribute(out_handle_, attribs | back_color); return orig_buffer_info.wAttributes; // return orig attribs } // print a range of formatted message to console void _print_range(const details::log_msg &msg, size_t start, size_t end) { - DWORD size = static_cast(end - start); - WriteConsoleA(out_handle_, msg.formatted.data() + start, size, nullptr, nullptr); + auto size = static_cast(end - start); + ::WriteConsoleA(out_handle_, msg.formatted.data() + start, size, nullptr, nullptr); } + + HANDLE out_handle_; + Mutex& _mutex; + std::unordered_map colors_; }; // @@ -113,14 +118,26 @@ private: // template class wincolor_stdout_sink : public wincolor_sink -{ +{ public: - wincolor_stdout_sink() - : wincolor_sink(GetStdHandle(STD_OUTPUT_HANDLE)) + wincolor_stdout_sink() + : wincolor_sink(GetStdHandle(STD_OUTPUT_HANDLE), details::os::stdout_mutex()) { } }; +template<> +class wincolor_stdout_sink : public wincolor_sink +{ + details::null_mutex _null_mutex; +public: + wincolor_stdout_sink() + : wincolor_sink(GetStdHandle(STD_OUTPUT_HANDLE), _null_mutex) + { + } + +}; + using wincolor_stdout_sink_mt = wincolor_stdout_sink; using wincolor_stdout_sink_st = wincolor_stdout_sink; @@ -132,11 +149,22 @@ class wincolor_stderr_sink : public wincolor_sink { public: wincolor_stderr_sink() - : wincolor_sink(GetStdHandle(STD_ERROR_HANDLE)) + : wincolor_sink(GetStdHandle(STD_ERROR_HANDLE), details::os::stderr_mutex()) { } }; +template<> +class wincolor_stderr_sink : public wincolor_sink +{ + details::null_mutex _null_mutex; +public: + wincolor_stderr_sink() + : wincolor_sink(GetStdHandle(STD_ERROR_HANDLE), _null_mutex) + { + } +}; + using wincolor_stderr_sink_mt = wincolor_stderr_sink; using wincolor_stderr_sink_st = wincolor_stderr_sink;