From 98addad8887432561462a23e14595a492b75e946 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 21 May 2017 01:36:03 +0300 Subject: [PATCH] Disable colors if terminal no attached and simplfy ansicolor_sink --- include/spdlog/details/log_msg.h | 6 +- include/spdlog/details/os.h | 501 +++++++++++++------------- include/spdlog/details/spdlog_impl.h | 8 +- include/spdlog/sinks/ansicolor_sink.h | 174 ++++----- 4 files changed, 335 insertions(+), 354 deletions(-) diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index 789a7338..5a24e639 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -19,7 +19,10 @@ namespace details struct log_msg { log_msg() = default; - log_msg(const std::string *loggers_name, level::level_enum lvl) : logger_name(loggers_name), level(lvl) + log_msg(const std::string *loggers_name, level::level_enum lvl) : + logger_name(loggers_name), + level(lvl), + msg_id(0) { #ifndef SPDLOG_NO_DATETIME time = os::now(); @@ -42,7 +45,6 @@ struct log_msg fmt::MemoryWriter raw; fmt::MemoryWriter formatted; size_t msg_id; - }; } } diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 91163efa..1361d1dc 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -29,7 +29,7 @@ #endif #include #include // _get_pid support -#include // _get_osfhandle support +#include // _get_osfhandle and _isatty support #ifdef __MINGW32__ #include @@ -56,82 +56,82 @@ namespace spdlog { -namespace details -{ -namespace os -{ + namespace details + { + namespace os + { -inline spdlog::log_clock::time_point now() -{ + inline spdlog::log_clock::time_point now() + { #if defined __linux__ && defined SPDLOG_CLOCK_COARSE - timespec ts; - ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); - return std::chrono::time_point( - std::chrono::duration_cast( - std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); + timespec ts; + ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); + return std::chrono::time_point( + std::chrono::duration_cast( + std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); #else - return log_clock::now(); + return log_clock::now(); #endif -} -inline std::tm localtime(const std::time_t &time_tt) -{ + } + inline std::tm localtime(const std::time_t &time_tt) + { #ifdef _WIN32 - std::tm tm; - localtime_s(&tm, &time_tt); + std::tm tm; + localtime_s(&tm, &time_tt); #else - std::tm tm; - localtime_r(&time_tt, &tm); + std::tm tm; + localtime_r(&time_tt, &tm); #endif - return tm; -} + return tm; + } -inline std::tm localtime() -{ - std::time_t now_t = time(nullptr); - return localtime(now_t); -} + inline std::tm localtime() + { + std::time_t now_t = time(nullptr); + return localtime(now_t); + } -inline std::tm gmtime(const std::time_t &time_tt) -{ + inline std::tm gmtime(const std::time_t &time_tt) + { #ifdef _WIN32 - std::tm tm; - gmtime_s(&tm, &time_tt); + std::tm tm; + gmtime_s(&tm, &time_tt); #else - std::tm tm; - gmtime_r(&time_tt, &tm); + std::tm tm; + gmtime_r(&time_tt, &tm); #endif - return tm; -} + return tm; + } -inline std::tm gmtime() -{ - std::time_t now_t = time(nullptr); - return gmtime(now_t); -} -inline bool operator==(const std::tm& tm1, const std::tm& tm2) -{ - return (tm1.tm_sec == tm2.tm_sec && - tm1.tm_min == tm2.tm_min && - tm1.tm_hour == tm2.tm_hour && - tm1.tm_mday == tm2.tm_mday && - tm1.tm_mon == tm2.tm_mon && - tm1.tm_year == tm2.tm_year && - tm1.tm_isdst == tm2.tm_isdst); -} + inline std::tm gmtime() + { + std::time_t now_t = time(nullptr); + return gmtime(now_t); + } + inline bool operator==(const std::tm& tm1, const std::tm& tm2) + { + return (tm1.tm_sec == tm2.tm_sec && + tm1.tm_min == tm2.tm_min && + tm1.tm_hour == tm2.tm_hour && + tm1.tm_mday == tm2.tm_mday && + tm1.tm_mon == tm2.tm_mon && + tm1.tm_year == tm2.tm_year && + tm1.tm_isdst == tm2.tm_isdst); + } -inline bool operator!=(const std::tm& tm1, const std::tm& tm2) -{ - return !(tm1 == tm2); -} + inline bool operator!=(const std::tm& tm1, const std::tm& tm2) + { + return !(tm1 == tm2); + } -// eol definition + // eol definition #if !defined (SPDLOG_EOL) #ifdef _WIN32 #define SPDLOG_EOL "\r\n" @@ -140,315 +140,322 @@ inline bool operator!=(const std::tm& tm1, const std::tm& tm2) #endif #endif -SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL; -SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1; + SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL; + SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1; -inline void prevent_child_fd(FILE *f) -{ + inline void prevent_child_fd(FILE *f) + { #ifdef _WIN32 - auto file_handle = (HANDLE)_get_osfhandle(_fileno(f)); - if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) - throw spdlog_ex("SetHandleInformation failed", errno); + auto file_handle = (HANDLE)_get_osfhandle(_fileno(f)); + if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) + throw spdlog_ex("SetHandleInformation failed", errno); #else - auto fd = fileno(f); - if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno); + auto fd = fileno(f); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno); #endif -} + } -//fopen_s on non windows for writing -inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode) -{ + //fopen_s on non windows for writing + inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode) + { #ifdef _WIN32 #ifdef SPDLOG_WCHAR_FILENAMES - *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); + *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); #else - *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); + *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); #endif #else //unix - *fp = fopen((filename.c_str()), mode.c_str()); + *fp = fopen((filename.c_str()), mode.c_str()); #endif #ifdef SPDLOG_PREVENT_CHILD_FD - if(*fp != nullptr) - prevent_child_fd(*fp); + if (*fp != nullptr) + prevent_child_fd(*fp); #endif - return *fp == nullptr; -} + return *fp == nullptr; + } -inline int remove(const filename_t &filename) -{ + inline int remove(const filename_t &filename) + { #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return _wremove(filename.c_str()); + return _wremove(filename.c_str()); #else - return std::remove(filename.c_str()); + return std::remove(filename.c_str()); #endif -} + } -inline int rename(const filename_t& filename1, const filename_t& filename2) -{ + inline int rename(const filename_t& filename1, const filename_t& filename2) + { #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return _wrename(filename1.c_str(), filename2.c_str()); + return _wrename(filename1.c_str(), filename2.c_str()); #else - return std::rename(filename1.c_str(), filename2.c_str()); + return std::rename(filename1.c_str(), filename2.c_str()); #endif -} + } -//Return if file exists -inline bool file_exists(const filename_t& filename) -{ + //Return if file exists + inline bool file_exists(const filename_t& filename) + { #ifdef _WIN32 #ifdef SPDLOG_WCHAR_FILENAMES - auto attribs = GetFileAttributesW(filename.c_str()); + auto attribs = GetFileAttributesW(filename.c_str()); #else - auto attribs = GetFileAttributesA(filename.c_str()); + auto attribs = GetFileAttributesA(filename.c_str()); #endif - return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); + return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); #else //common linux/unix all have the stat system call - struct stat buffer; - return (stat (filename.c_str(), &buffer) == 0); + struct stat buffer; + return (stat(filename.c_str(), &buffer) == 0); #endif -} + } -//Return file size according to open FILE* object -inline size_t filesize(FILE *f) -{ - if (f == nullptr) - throw spdlog_ex("Failed getting file size. fd is null"); + //Return file size according to open FILE* object + inline size_t filesize(FILE *f) + { + if (f == nullptr) + throw spdlog_ex("Failed getting file size. fd is null"); #ifdef _WIN32 - int fd = _fileno(f); + int fd = _fileno(f); #if _WIN64 //64 bits - struct _stat64 st; - if (_fstat64(fd, &st) == 0) - return st.st_size; + struct _stat64 st; + if (_fstat64(fd, &st) == 0) + return st.st_size; #else //windows 32 bits - long ret = _filelength(fd); - if (ret >= 0) - return static_cast(ret); + long ret = _filelength(fd); + if (ret >= 0) + return static_cast(ret); #endif #else // unix - int fd = fileno(f); - //64 bits(but not in osx, where fstat64 is deprecated) + int fd = fileno(f); + //64 bits(but not in osx, where fstat64 is deprecated) #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) - struct stat64 st; - if (fstat64(fd, &st) == 0) - return static_cast(st.st_size); + struct stat64 st; + if (fstat64(fd, &st) == 0) + return static_cast(st.st_size); #else // unix 32 bits or osx - struct stat st; - if (fstat(fd, &st) == 0) - return static_cast(st.st_size); + struct stat st; + if (fstat(fd, &st) == 0) + return static_cast(st.st_size); #endif #endif - throw spdlog_ex("Failed getting file size from fd", errno); -} + throw spdlog_ex("Failed getting file size from fd", errno); + } -//Return utc offset in minutes or throw spdlog_ex on failure -inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) -{ + //Return utc offset in minutes or throw spdlog_ex on failure + inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) + { #ifdef _WIN32 #if _WIN32_WINNT < _WIN32_WINNT_WS08 - TIME_ZONE_INFORMATION tzinfo; - auto rv = GetTimeZoneInformation(&tzinfo); + TIME_ZONE_INFORMATION tzinfo; + auto rv = GetTimeZoneInformation(&tzinfo); #else - DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - auto rv = GetDynamicTimeZoneInformation(&tzinfo); + DYNAMIC_TIME_ZONE_INFORMATION tzinfo; + auto rv = GetDynamicTimeZoneInformation(&tzinfo); #endif - if (rv == TIME_ZONE_ID_INVALID) - throw spdlog::spdlog_ex("Failed getting timezone info. ", errno); + if (rv == TIME_ZONE_ID_INVALID) + throw spdlog::spdlog_ex("Failed getting timezone info. ", errno); - int offset = -tzinfo.Bias; - if (tm.tm_isdst) - offset -= tzinfo.DaylightBias; - else - offset -= tzinfo.StandardBias; - return offset; + int offset = -tzinfo.Bias; + if (tm.tm_isdst) + offset -= tzinfo.DaylightBias; + else + offset -= tzinfo.StandardBias; + return offset; #else #if defined(sun) || defined(__sun) - // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris - struct helper - { - static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime()) - { - int local_year = localtm.tm_year + (1900 - 1); - int gmt_year = gmtm.tm_year + (1900 - 1); + // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris + struct helper + { + static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime()) + { + int local_year = localtm.tm_year + (1900 - 1); + int gmt_year = gmtm.tm_year + (1900 - 1); - long int days = ( - // difference in day of year - localtm.tm_yday - gmtm.tm_yday + long int days = ( + // difference in day of year + localtm.tm_yday - gmtm.tm_yday - // + intervening leap days - + ((local_year >> 2) - (gmt_year >> 2)) - - (local_year / 100 - gmt_year / 100) - + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) + // + intervening leap days + + ((local_year >> 2) - (gmt_year >> 2)) + - (local_year / 100 - gmt_year / 100) + + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) - // + difference in years * 365 */ - + (long int)(local_year - gmt_year) * 365 - ); + // + difference in years * 365 */ + + (long int)(local_year - gmt_year) * 365 + ); - long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); - long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); - long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); + long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); + long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); + long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); - return secs; - } - }; + return secs; + } + }; - long int offset_seconds = helper::calculate_gmt_offset(tm); + long int offset_seconds = helper::calculate_gmt_offset(tm); #else - long int offset_seconds = tm.tm_gmtoff; + long int offset_seconds = tm.tm_gmtoff; #endif - return static_cast(offset_seconds / 60); + return static_cast(offset_seconds / 60); #endif -} + } -//Return current thread id as size_t -//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013) -inline size_t _thread_id() -{ + //Return current thread id as size_t + //It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013) + inline size_t _thread_id() + { #ifdef _WIN32 - return static_cast(::GetCurrentThreadId()); + return static_cast(::GetCurrentThreadId()); #elif __linux__ # if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) # define SYS_gettid __NR_gettid # endif - return static_cast(syscall(SYS_gettid)); + return static_cast(syscall(SYS_gettid)); #elif __FreeBSD__ - long tid; - thr_self(&tid); - return static_cast(tid); + long tid; + thr_self(&tid); + return static_cast(tid); #else //Default to standard C++11 (OSX and other Unix) - return static_cast(std::hash()(std::this_thread::get_id())); + return static_cast(std::hash()(std::this_thread::get_id())); #endif -} + } -//Return current thread id as size_t (from thread local storage) -inline size_t thread_id() -{ + //Return current thread id as size_t (from thread local storage) + inline size_t thread_id() + { #if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local) - return _thread_id(); + return _thread_id(); #else - static thread_local const size_t tid = _thread_id(); - return tid; + static thread_local const size_t tid = _thread_id(); + return tid; #endif -} + } -// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) + // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #define SPDLOG_FILENAME_T(s) L ## s -inline std::string filename_to_str(const filename_t& filename) -{ - std::wstring_convert, wchar_t> c; - return c.to_bytes(filename); -} + inline std::string filename_to_str(const filename_t& filename) + { + std::wstring_convert, wchar_t> c; + return c.to_bytes(filename); + } #else #define SPDLOG_FILENAME_T(s) s -inline std::string filename_to_str(const filename_t& filename) -{ - return filename; -} + inline std::string filename_to_str(const filename_t& filename) + { + return filename; + } #endif -inline std::string errno_to_string(char [256], char* res) -{ - return std::string(res); -} + inline std::string errno_to_string(char[256], char* res) + { + return std::string(res); + } -inline std::string errno_to_string(char buf[256], int res) -{ - if (res == 0) - { - return std::string(buf); - } - else - { - return "Unknown error"; - } -} + inline std::string errno_to_string(char buf[256], int res) + { + if (res == 0) { + return std::string(buf); + } + else { + return "Unknown error"; + } + } -// Return errno string (thread safe) -inline std::string errno_str(int err_num) -{ - char buf[256]; - SPDLOG_CONSTEXPR auto buf_size = sizeof(buf); + // Return errno string (thread safe) + inline std::string errno_str(int err_num) + { + char buf[256]; + SPDLOG_CONSTEXPR auto buf_size = sizeof(buf); #ifdef _WIN32 - if(strerror_s(buf, buf_size, err_num) == 0) - return std::string(buf); - else - return "Unknown error"; + if (strerror_s(buf, buf_size, err_num) == 0) + return std::string(buf); + else + return "Unknown error"; #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \ ((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version - if (strerror_r(err_num, buf, buf_size) == 0) - return std::string(buf); - else - return "Unknown error"; + if (strerror_r(err_num, buf, buf_size) == 0) + return std::string(buf); + else + return "Unknown error"; #else // gnu version (might not use the given buf, so its retval pointer must be used) - auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type - return errno_to_string(buf, err); // use overloading to select correct stringify function + auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type + return errno_to_string(buf, err); // use overloading to select correct stringify function #endif -} + } -inline int pid() -{ + inline int pid() + { #ifdef _WIN32 - return ::_getpid(); + return ::_getpid(); #else - return static_cast(::getpid()); + return static_cast(::getpid()); #endif -} + } -// Detrmine if the terminal supports colors -// Source: https://github.com/agauniyal/rang/ -inline bool is_color_terminal() -{ + // Detrmine if the terminal supports colors + // Source: https://github.com/agauniyal/rang/ + inline bool is_color_terminal() + { #ifdef _WIN32 - return true; + return true; #else - static constexpr const char* Terms[] = - { - "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", - "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm" - }; + 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; - } + 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; - }); - return result; + static const bool result = std::any_of( + std::begin(Terms), std::end(Terms), [&](const char* term) { + return std::strstr(env_p, term) != nullptr; + }); + return result; #endif -} + } -} //os -} //details + // Detrmine if the terminal attached + // Source: https://github.com/agauniyal/rang/ + bool in_terminal(FILE* file) + { + +#ifdef _WIN32 + return _isatty(_fileno(file)) ? true : false; +#else + return isatty(fileno(file)) ? true : false; +#endif + } + } //os + } //details } //spdlog diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index 79d3ac45..2552d952 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -137,25 +137,25 @@ inline std::shared_ptr spdlog::stderr_color_st(const std::string inline std::shared_ptr spdlog::stdout_color_mt(const std::string& logger_name) { - auto sink = std::make_shared(spdlog::sinks::stdout_sink_mt::instance()); + auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stdout_color_st(const std::string& logger_name) { - auto sink = std::make_shared(spdlog::sinks::stdout_sink_st::instance()); + auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stderr_color_mt(const std::string& logger_name) { - auto sink = std::make_shared(spdlog::sinks::stderr_sink_mt::instance()); + auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stderr_color_st(const std::string& logger_name) { - auto sink = std::make_shared(spdlog::sinks::stderr_sink_st::instance()); + auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } #endif diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index 0e5e53c6..dc943941 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -10,118 +10,90 @@ #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. + */ + template + class ansicolor_sink SPDLOG_FINAL: public base_sink + { + public: + ansicolor_sink(FILE* file): _target_file(file) + { + using namespace ansi_color_codes; + should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal(); + colors_[level::trace] = "\033[36m"; // cyan; + colors_[level::debug] = "\033[36m"; // cyan; + colors_[level::info] = "\033[1m";// bold; + colors_[level::warn] = "\033[33m\033[1m"; // yellow_bold; + colors_[level::err] = "\033[31m\033[1m"; // red_bold; + colors_[level::critical] = "\033[1m\033[41m"; // bold_red_bg; + colors_[level::off] = "\033[00m"; //reset; + } + virtual ~ansicolor_sink() + { + flush(); + } - ansicolor_sink(const ansicolor_sink& other) = delete; - ansicolor_sink& operator=(const ansicolor_sink& other) = delete; + void flush() override + { + fflush(_target_file); + } - 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); - - /// 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"; - - /// 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: + virtual 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_) + { + const std::string& prefix = colors_[msg.level]; + const std::string& suffix = ansi_color_codes::reset; + fwrite(prefix, sizeof(char), prefix.size(), _target_file); + fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), _target_file); + fwrite(suffix, sizeof(char), suffix.size(), _target_file); + } + else + { + fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), _target_file); + } + } + private: + bool should_do_colors_; + std::unordered_map colors_; + }; -protected: - bool is_color_terminal_; - sink_ptr sink_; - std::map colors_; -}; + template + class ansicolor_stdout_sink: public ansicolor_sink + { + public: + ansicolor_stdout_sink(): ansicolor_sink(stdout) + {} + }; -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; -} + template + class ansicolor_stderr_sink: public ansicolor_sink + { + public: + ansicolor_stderr_sink(): ansicolor_sink(stderr) + {} + }; -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); - } -} + typedef ansicolor_stdout_sink ansicolor_stdout_sink_mt; + typedef ansicolor_stdout_sink ansicolor_stdout_sink_st; -inline void ansicolor_sink::flush() -{ - sink_->flush(); -} + typedef ansicolor_stderr_sink ansicolor_stderr_sink_mt; + typedef ansicolor_stderr_sink ansicolor_stderr_sink_st; -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(); -} - -} // namespace sinks + } // namespace sinks } // namespace spdlog