From 924ef84241d9891a9abac4efe41934d928723b9d Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 18 Apr 2018 02:04:10 +0300 Subject: [PATCH] Refactred spdlog.h and console sinks. Added global lock for all console sinks (traits) --- include/spdlog/details/async_logger_impl.h | 20 ++-- include/spdlog/details/registry.h | 12 ++- include/spdlog/details/traits.h | 45 ++++++++ include/spdlog/sinks/ansicolor_sink.h | 117 ++++++++++----------- include/spdlog/sinks/stdout_sinks.h | 65 +++++------- include/spdlog/sinks/wincolor_sink.h | 74 +++---------- include/spdlog/spdlog.h | 85 ++++++++------- 7 files changed, 206 insertions(+), 212 deletions(-) create mode 100644 include/spdlog/details/traits.h diff --git a/include/spdlog/details/async_logger_impl.h b/include/spdlog/details/async_logger_impl.h index aa617fa2..8c80cd2f 100644 --- a/include/spdlog/details/async_logger_impl.h +++ b/include/spdlog/details/async_logger_impl.h @@ -37,9 +37,7 @@ inline spdlog::async_logger::async_logger( // send the log message to the thread pool inline void spdlog::async_logger::_sink_it(details::log_msg &msg) -{ - try - { +{ #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) _incr_msg_counter(msg); #endif @@ -50,16 +48,7 @@ inline void spdlog::async_logger::_sink_it(details::log_msg &msg) else { throw spdlog_ex("async log: thread pool doens't exist anymore"); - } - } - catch (const std::exception &ex) - { - _err_handler(ex.what()); - } - catch (...) - { - _err_handler("Unknown exception in async logger " + _name); - } + } } // send flush request to the thread pool @@ -99,6 +88,11 @@ inline void spdlog::async_logger::_backend_log(details::log_msg &incoming_log_ms { _err_handler("Unknown exception in async logger " + _name); } + + if (_should_flush(incoming_log_msg)) + { + _backend_flush(); + } } inline void spdlog::async_logger::_backend_flush() diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index bda9bb7b..0e4b0dec 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -148,8 +148,16 @@ public: void drop_all() { - std::lock_guard lock(_mutex); - _loggers.clear(); + { + std::lock_guard lock(_mutex); + _loggers.clear(); + } + + { + std::lock_guard lock(_tp_mutex); + _tp.reset(); + } + } Mutex &tp_mutex() diff --git a/include/spdlog/details/traits.h b/include/spdlog/details/traits.h new file mode 100644 index 00000000..75fa3987 --- /dev/null +++ b/include/spdlog/details/traits.h @@ -0,0 +1,45 @@ +#pragma once +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +namespace spdlog { + namespace details { + struct console_stdout_trait + { + static FILE* stream() {return stdout;} +#ifdef _WIN32 + static HANDLE handle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } +#endif + }; + + struct console_stderr_trait + { + static FILE* stream() { return stdout; } +#ifdef _WIN32 + static HANDLE handle() { return ::GetStdHandle(STD_ERROR_HANDLE); } +#endif + }; + + struct console_mutex_trait + { + using mutex_t = std::mutex; + static mutex_t& console_mutex() + { + static auto mutex = mutex_t{}; + return mutex; + } + }; + + struct console_null_mutex_trait + { + using mutex_t = null_mutex; + static mutex_t& console_mutex() + { + static auto mutex = mutex_t{}; + return mutex; + } + }; + } +} diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index aaa09205..25697943 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -5,12 +5,14 @@ #pragma once -#include "../common.h" +#include "../details/null_mutex.h" #include "../details/os.h" -#include "base_sink.h" +#include "../details/traits.h" #include #include +#include +#include namespace spdlog { namespace sinks { @@ -20,12 +22,15 @@ namespace sinks { * of the message. * If no color terminal detected, omit the escape codes. */ -template -class ansicolor_sink : public base_sink -{ +template +class ansicolor_sink : public sink +{ public: - explicit ansicolor_sink(FILE *file) - : target_file_(file) + using mutex_t = typename ConsoleMutexTrait::mutex_t; + ansicolor_sink() + : target_file_(StdoutTrait::stream()), + _mutex(ConsoleMutexTrait::mutex()) + { should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal(); colors_[level::trace] = white; @@ -42,9 +47,12 @@ public: _flush(); } + ansicolor_sink(const ansicolor_sink &other) = delete; + ansicolor_sink &operator=(const ansicolor_sink &other) = delete; + void set_color(level::level_enum color_level, const std::string &color) { - std::lock_guard lock(base_sink::_mutex); + std::lock_guard lock(_mutex); colors_[color_level] = color; } @@ -78,35 +86,39 @@ public: const std::string on_cyan = "\033[46m"; const std::string on_white = "\033[47m"; -protected: - void _sink_it(const details::log_msg &msg) override - { - // Wrap the originally formatted message in color codes. - // If color is not supported in the terminal, log as is instead. - if (should_do_colors_ && msg.color_range_end > msg.color_range_start) - { - // before color range - _print_range(msg, 0, msg.color_range_start); - // in color range - _print_ccode(colors_[msg.level]); - _print_range(msg, msg.color_range_start, msg.color_range_end); - _print_ccode(reset); - // after color range - _print_range(msg, msg.color_range_end, msg.formatted.size()); - } - else // no color - { - _print_range(msg, 0, msg.formatted.size()); - } - _flush(); - } - void _flush() override - { - fflush(target_file_); - } + void log(const details::log_msg &msg) SPDLOG_FINAL override + { + // Wrap the originally formatted message in color codes. + // If color is not supported in the terminal, log as is instead. + std::lock_guard lock(_mutex); + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) + { + // before color range + _print_range(msg, 0, msg.color_range_start); + // in color range + _print_ccode(colors_[msg.level]); + _print_range(msg, msg.color_range_start, msg.color_range_end); + _print_ccode(reset); + // after color range + _print_range(msg, msg.color_range_end, msg.formatted.size()); + } + else // no color + { + _print_range(msg, 0, msg.formatted.size()); + } + fflush(target_file_); + } -private: + void flush() SPDLOG_FINAL override + { + std::lock_guard lock(_mutex); + fflush(target_file_); + } + + +private: + void _print_ccode(const std::string &color_code) { fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); @@ -115,36 +127,19 @@ private: { fwrite(msg.formatted.data() + start, sizeof(char), end - start, target_file_); } + FILE *target_file_; + mutex_t & _mutex; + bool should_do_colors_; std::unordered_map colors_; }; +#ifndef _WIN32 +using stdout_color_mt = ansicolor_sink; +using stdout_color_st = ansicolor_sink; -template -class ansicolor_stdout_sink : public ansicolor_sink -{ -public: - ansicolor_stdout_sink() - : ansicolor_sink(stdout) - { - } -}; - -using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; -using ansicolor_stdout_sink_st = ansicolor_stdout_sink; - -template -class ansicolor_stderr_sink : public ansicolor_sink -{ -public: - ansicolor_stderr_sink() - : ansicolor_sink(stderr) - { - } -}; - -using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; -using ansicolor_stderr_sink_st = ansicolor_stderr_sink; - +using stderr_color_mt = ansicolor_sink; +using stderr_color_st = ansicolor_sink; +#endif } // namespace sinks } // namespace spdlog diff --git a/include/spdlog/sinks/stdout_sinks.h b/include/spdlog/sinks/stdout_sinks.h index f0911f4a..a0be0a33 100644 --- a/include/spdlog/sinks/stdout_sinks.h +++ b/include/spdlog/sinks/stdout_sinks.h @@ -6,7 +6,7 @@ #pragma once #include "../details/null_mutex.h" -#include "base_sink.h" +#include "../details/traits.h" #include #include @@ -15,53 +15,40 @@ namespace spdlog { namespace sinks { -template -class stdout_sink SPDLOG_FINAL : public base_sink -{ - using MyType = stdout_sink; - +template +class stdout_sink : public sink +{ public: - explicit stdout_sink() = default; + using mutex_t = typename ConsoleMutexTrait::mutex_t; + stdout_sink() : + _mutex(ConsoleMutexTrait::console_mutex()), + _file(StdoutTrait::stream()) {} + ~stdout_sink() = default; -protected: - void _sink_it(const details::log_msg &msg) override + stdout_sink(const stdout_sink &other) = delete; + stdout_sink &operator=(const stdout_sink &other) = delete; + + void log(const details::log_msg &msg) override { - fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout); - _flush(); + std::lock_guard lock(_mutex); + fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), _file); + fflush(StdoutTrait::stream()); } - void _flush() override + void flush() override { - fflush(stdout); + std::lock_guard lock(_mutex); + fflush(StdoutTrait::stream()); } +private: + typename mutex_t& _mutex; + FILE* _file; }; -using stdout_sink_mt = stdout_sink; -using stdout_sink_st = stdout_sink; - -template -class stderr_sink SPDLOG_FINAL : public base_sink -{ - using MyType = stderr_sink; - -public: - explicit stderr_sink() = default; - -protected: - void _sink_it(const details::log_msg &msg) override - { - fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr); - _flush(); - } - - void _flush() override - { - fflush(stderr); - } -}; - -using stderr_sink_mt = stderr_sink; -using stderr_sink_st = stderr_sink; +using stdout_sink_mt = stdout_sink; +using stdout_sink_st = stdout_sink; +using stderr_sink_mt = stdout_sink; +using stderr_sink_st = stdout_sink; } // namespace sinks } // namespace spdlog diff --git a/include/spdlog/sinks/wincolor_sink.h b/include/spdlog/sinks/wincolor_sink.h index c44c0023..e377c7c0 100644 --- a/include/spdlog/sinks/wincolor_sink.h +++ b/include/spdlog/sinks/wincolor_sink.h @@ -7,7 +7,7 @@ #include "../common.h" #include "../details/null_mutex.h" -#include "base_sink.h" +#include "../details/traits.h" #include #include @@ -19,11 +19,12 @@ namespace spdlog { namespace sinks { /* * Windows color console sink. Uses WriteConsoleA to write to the console with colors - */ -template + */ +template class wincolor_sink : public sink { public: + const WORD BOLD = FOREGROUND_INTENSITY; const WORD RED = FOREGROUND_RED; const WORD GREEN = FOREGROUND_GREEN; @@ -31,8 +32,9 @@ public: const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; - wincolor_sink(HANDLE std_handle, Mutex& stdout_mutex) - : out_handle_(std_handle), _mutex(stdout_mutex) + wincolor_sink() + : out_handle_(HandleTrait::handle()), + _mutex(ConsoleMutexTrait::console_mutex()) { colors_[level::trace] = WHITE; colors_[level::debug] = CYAN; @@ -55,13 +57,13 @@ public: // change the color for the given level void set_color(level::level_enum level, WORD color) { - std::lock_guard lock(base_sink::_mutex); + std::lock_guard lock(_mutex); colors_[level] = color; } void log(const details::log_msg &msg) SPDLOG_FINAL override { - std::lock_guard lock(_mutex); + std::lock_guard lock(_mutex); if (msg.color_range_end > msg.color_range_start) { @@ -85,9 +87,9 @@ public: { // windows console always flushed? } - private: + using mutex_t = typename ConsoleMutexTrait::mutex_t; // set color and return the orig console attributes (for resetting later) WORD set_console_attribs(WORD attribs) { @@ -109,64 +111,18 @@ private: } HANDLE out_handle_; - Mutex& _mutex; + mutex_t &_mutex; std::unordered_map colors_; }; // // windows color console to stdout // -template -class wincolor_stdout_sink : public wincolor_sink -{ -public: - 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; - -// -// windows color console to stderr -// -template -class wincolor_stderr_sink : public wincolor_sink -{ -public: - wincolor_stderr_sink() - : 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; +using stdout_color_mt = wincolor_sink; +using stdout_color_st = wincolor_sink; +using stderr_color_mt = wincolor_sink; +using stderr_color_st = wincolor_sink; } // namespace sinks } // namespace spdlog diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index a7544926..285309f5 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -176,48 +176,57 @@ inline std::shared_ptr daily_logger_st(const std::string &logger_name, c return Factory::template create(logger_name, filename, hour, minute); } -/////////////////////////////////////////////////////////////////////////////// -// stdout and stderr loggers // -// multi threaded and colored: -// spdlog::console("name") -// spdlog::console("name") +// color console logger // -// single threaded and colored: -// spdlog::console("name") -// spdlog::console("name") -// -// multi threaded, no color: -// spdlog::console("name") -// spdlog::console("name") -// -// single threaded, no color: -// spdlog::console("name") -// spdlog::console("name") -/////////////////////////////////////////////////////////////////////////////// - -#if defined _WIN32 // window color console -using stdout_color_mt = sinks::wincolor_stdout_sink_mt; -using stdout_color_st = sinks::wincolor_stdout_sink_st; -using stderr_color_mt = sinks::wincolor_stderr_sink_mt; -using stderr_color_st = sinks::wincolor_stderr_sink_st; -#else // ansi color console -using stdout_color_mt = sinks::ansicolor_stdout_sink_mt; -using stdout_color_st = sinks::ansicolor_stdout_sink_st; -using stderr_color_mt = sinks::ansicolor_stderr_sink_mt; -using stderr_color_st = sinks::ansicolor_stderr_sink_st; -#endif -// no color console -using stdout_mt = sinks::stdout_sink_mt; -using stdout_st = sinks::stdout_sink_st; -using stderr_mt = sinks::stderr_sink_mt; -using stderr_st = sinks::stderr_sink_st; - -template -inline std::shared_ptr console(const std::string &logger_name) +template +inline std::shared_ptr stdout_color_mt(const std::string &logger_name) { - return Factory::template create(logger_name); + return Factory::template create(logger_name); } +template +inline std::shared_ptr stdout_color_st(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +inline std::shared_ptr stderr_color_mt(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +inline std::shared_ptr stderr_color_st(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +// console loggers (no colors) +template +inline std::shared_ptr stdout_logger_mt(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +inline std::shared_ptr stdout_logger_st(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +inline std::shared_ptr stderr_logger_mt(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + +template +inline std::shared_ptr stderr_logger_st(const std::string &logger_name) +{ + return Factory::template create(logger_name); +} + #ifdef SPDLOG_ENABLE_SYSLOG // Create and register a syslog logger