diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 4d9f60a5..637962a8 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -401,6 +402,32 @@ inline int pid() } + +// Detrmine if the terminal supports colors +// Source: https://github.com/agauniyal/rang/ +bool is_color_terminal() +{ +#ifdef _WIN32 + return true; +#else + static constexpr const char* Terms[] = { + "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", + "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm" + }; + + const char *env_p = std::getenv("TERM"); + if (env_p == nullptr) { + return false; + } + + static const bool result = std::any_of( + std::begin(Terms), std::end(Terms), [&](const char* term) { + return std::strstr(env_p, term) != nullptr; + }); +#endif +} + + } //os } //details } //spdlog diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index d9df4349..33d02445 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -7,110 +7,119 @@ #include #include +#include #include #include namespace spdlog { -namespace sinks -{ + namespace sinks + { -/** - * @brief The ansi_color_sink is a decorator around another sink and prefixes - * the output with an ANSI escape sequence color code depending on the severity - * of the message. - */ -class ansicolor_sink SPDLOG_FINAL : public sink -{ -public: - ansicolor_sink(sink_ptr wrapped_sink); - virtual ~ansicolor_sink(); + /** + * @brief The ansi_color_sink is a decorator around another sink and prefixes + * the output with an ANSI escape sequence color code depending on the severity + * of the message. + */ + class ansicolor_sink SPDLOG_FINAL: public sink + { + public: + ansicolor_sink(sink_ptr wrapped_sink); + virtual ~ansicolor_sink(); - ansicolor_sink(const ansicolor_sink& other) = delete; - ansicolor_sink& operator=(const ansicolor_sink& other) = delete; + ansicolor_sink(const ansicolor_sink& other) = delete; + ansicolor_sink& operator=(const ansicolor_sink& other) = delete; - virtual void log(const details::log_msg& msg) override; - virtual void flush() override; + virtual void log(const details::log_msg& msg) override; + virtual void flush() override; - void set_color(level::level_enum color_level, const std::string& color); + void set_color(level::level_enum color_level, const std::string& color); - /// Formatting codes - const std::string reset = "\033[00m"; - const std::string bold = "\033[1m"; - const std::string dark = "\033[2m"; - const std::string underline = "\033[4m"; - const std::string blink = "\033[5m"; - const std::string reverse = "\033[7m"; - const std::string concealed = "\033[8m"; + /// Formatting codes + const std::string reset = "\033[00m"; + const std::string bold = "\033[1m"; + const std::string dark = "\033[2m"; + const std::string underline = "\033[4m"; + const std::string blink = "\033[5m"; + const std::string reverse = "\033[7m"; + const std::string concealed = "\033[8m"; - // Foreground colors - const std::string grey = "\033[30m"; - const std::string red = "\033[31m"; - const std::string green = "\033[32m"; - const std::string yellow = "\033[33m"; - const std::string blue = "\033[34m"; - const std::string magenta = "\033[35m"; - const std::string cyan = "\033[36m"; - const std::string white = "\033[37m"; + // Foreground colors + const std::string grey = "\033[30m"; + const std::string red = "\033[31m"; + const std::string green = "\033[32m"; + const std::string yellow = "\033[33m"; + const std::string blue = "\033[34m"; + const std::string magenta = "\033[35m"; + const std::string cyan = "\033[36m"; + const std::string white = "\033[37m"; - /// Background colors - const std::string on_grey = "\033[40m"; - const std::string on_red = "\033[41m"; - const std::string on_green = "\033[42m"; - const std::string on_yellow = "\033[43m"; - const std::string on_blue = "\033[44m"; - const std::string on_magenta = "\033[45m"; - const std::string on_cyan = "\033[46m"; - const std::string on_white = "\033[47m"; + /// Background colors + const std::string on_grey = "\033[40m"; + const std::string on_red = "\033[41m"; + const std::string on_green = "\033[42m"; + const std::string on_yellow = "\033[43m"; + const std::string on_blue = "\033[44m"; + const std::string on_magenta = "\033[45m"; + const std::string on_cyan = "\033[46m"; + const std::string on_white = "\033[47m"; -protected: - sink_ptr sink_; - std::map colors_; -}; + protected: + bool is_color_terminal_; + sink_ptr sink_; + std::map colors_; + }; -inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink) -{ - colors_[level::trace] = cyan; - colors_[level::debug] = cyan; - colors_[level::info] = bold; - colors_[level::warn] = yellow + bold; - colors_[level::err] = red + bold; - colors_[level::critical] = bold + on_red; - colors_[level::off] = reset; -} + inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink): sink_(wrapped_sink) + { + is_color_terminal_ = details::os::is_color_terminal(); + colors_[level::trace] = cyan; + colors_[level::debug] = cyan; + colors_[level::info] = bold; + colors_[level::warn] = yellow + bold; + colors_[level::err] = red + bold; + colors_[level::critical] = bold + on_red; + colors_[level::off] = reset; + } -inline void ansicolor_sink::log(const details::log_msg& msg) -{ - // Wrap the originally formatted message in color codes - const std::string& prefix = colors_[msg.level]; - const std::string& s = msg.formatted.str(); - const std::string& suffix = reset; - details::log_msg m; - m.level = msg.level; - m.logger_name = msg.logger_name; - m.time = msg.time; - m.thread_id = msg.thread_id; - m.formatted << prefix << s << suffix; - sink_->log(m); -} + inline void ansicolor_sink::log(const details::log_msg& msg) + { + // Wrap the originally formatted message in color codes. + // If color is not supported in the terminal, log as is instead. + if (is_color_terminal_) { + const std::string& prefix = colors_[msg.level]; + const std::string& s = msg.formatted.str(); + const std::string& suffix = reset; + details::log_msg m; + m.level = msg.level; + m.logger_name = msg.logger_name; + m.time = msg.time; + m.thread_id = msg.thread_id; + m.formatted << prefix << s << suffix; + sink_->log(m); + } + else { + sink_->log(msg); + } + } -inline void ansicolor_sink::flush() -{ - sink_->flush(); -} + inline void ansicolor_sink::flush() + { + sink_->flush(); + } -inline void ansicolor_sink::set_color(level::level_enum color_level, const std::string& color) -{ - colors_[color_level] = color; -} + inline void ansicolor_sink::set_color(level::level_enum color_level, const std::string& color) + { + colors_[color_level] = color; + } -inline ansicolor_sink::~ansicolor_sink() -{ - flush(); -} + inline ansicolor_sink::~ansicolor_sink() + { + flush(); + } -} // namespace sinks + } // namespace sinks } // namespace spdlog