diff --git a/README.md b/README.md index 9a411fdd..52c71726 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Time needed to log 1,000,000 lines in asynchronous mode, i.e. the time it takes ## Buck -The test, examples and benchmarks can be run using [Buck](https://www.buckbuild.com): +The tests, examples and benchmarks can be run using [Buck](https://www.buckbuild.com): ```bash buck run example/ @@ -131,11 +131,11 @@ int main(int, char*[]) rotating_logger->info("This is another message with custom format"); - // Runtime log levels - spd::set_level(spd::level::info); //Set global log level to info - console->debug("This message shold not be displayed!"); - console->set_level(spd::level::debug); // Set specific logger's log level - console->debug("This message shold be displayed.."); + // Runtime log levels + spd::set_level(spd::level::info); //Set global log level to info + console->debug("This message shold not be displayed!"); + console->set_level(spd::level::debug); // Set specific logger's log level + console->debug("This message shold be displayed.."); // Compile time log levels // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON @@ -159,13 +159,13 @@ int main(int, char*[]) err_handler_example(); // Apply a function on all registered loggers - spd::apply_all([&](std::shared_ptr l) + spd::apply_all([&](std::shared_ptr l) { l->info("End of example."); }); // Release and close all loggers - spdlog::drop_all(); + spd::drop_all(); } // Exceptions will only be thrown upon failed logger or sink construction (not during logging) catch (const spd::spdlog_ex& ex) @@ -178,7 +178,7 @@ int main(int, char*[]) void async_example() { size_t q_size = 4096; //queue size must be power of 2 - spdlog::set_async_mode(q_size); + spd::set_async_mode(q_size); auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); for (int i = 0; i < 100; ++i) async_file->info("Async message #{}", i); @@ -216,7 +216,7 @@ void user_defined_example() // void err_handler_example() { - spdlog::set_error_handler([](const std::string& msg) { + spd::set_error_handler([](const std::string& msg) { std::cerr << "my err handler: " << msg << std::endl; }); // (or logger->set_error_handler(..) to set for specific logger) diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h index 76d70a3d..a86d2190 100644 --- a/include/spdlog/async_logger.h +++ b/include/spdlog/async_logger.h @@ -31,7 +31,7 @@ namespace details class async_log_helper; } -class async_logger :public logger +class async_logger SPDLOG_FINAL :public logger { public: template @@ -61,7 +61,7 @@ public: const std::function& worker_teardown_cb = nullptr); //Wait for the queue to be empty, and flush synchronously - //Warning: this can potentialy last forever as we wait it to complete + //Warning: this can potentially last forever as we wait it to complete void flush() override; // Error handler diff --git a/include/spdlog/common.h b/include/spdlog/common.h index a0a227ef..e9fa372e 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -29,6 +29,11 @@ #define SPDLOG_CONSTEXPR constexpr #endif +// See tweakme.h +#if !defined(SPDLOG_FINAL) +#define SPDLOG_FINAL +#endif + #if defined(__GNUC__) || defined(__clang__) #define SPDLOG_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 92a0f4cd..faa23cbe 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -9,8 +9,6 @@ // If the internal queue of log messages reaches its max size, // then the client call will block until there is more room. // -// If the back thread throws during logging, a spdlog::spdlog_ex exception -// will be thrown in client's thread when tries to log the next message #pragma once @@ -62,11 +60,15 @@ async_msg(async_msg&& other) SPDLOG_NOEXCEPT: logger_name(std::move(other.logger_name)), level(std::move(other.level)), time(std::move(other.time)), + thread_id(other.thread_id), txt(std::move(other.txt)), msg_type(std::move(other.msg_type)) {} - async_msg(async_msg_type m_type):msg_type(m_type) + async_msg(async_msg_type m_type): + level(level::info), + thread_id(0), + msg_type(m_type) {} async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT @@ -177,7 +179,7 @@ private: void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush); - // sleep,yield or return immediatly using the time passed since last message as a hint + // sleep,yield or return immediately using the time passed since last message as a hint static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time); // wait until the queue is empty diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 074d9b83..84ec722d 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -7,7 +7,6 @@ // Helper class for file sink // When failing to open a file, retry several times(5) with small delay between the tries(10 ms) -// Can be set to auto flush on every line // Throw spdlog_ex exception on errors #include diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index 5bb85f67..02ebc875 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -18,11 +18,11 @@ template inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end): _name(logger_name), _sinks(begin, end), - _formatter(std::make_shared("%+")) + _formatter(std::make_shared("%+")), + _level(level::info), + _flush_level(level::off), + _last_err_time(0) { - _level = level::info; - _flush_level = level::off; - _last_err_time = 0; _err_handler = [this](const std::string &msg) { this->_default_err_handler(msg); @@ -195,6 +195,63 @@ inline void spdlog::logger::critical(const T& msg) log(level::critical, msg); } +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +#include + +template +inline void spdlog::logger::log(level::level_enum lvl, const wchar_t* msg) +{ + std::wstring_convert > conv; + + log(lvl, conv.to_bytes(msg)); +} + +template +inline void spdlog::logger::log(level::level_enum lvl, const wchar_t* fmt, const Args&... args) +{ + fmt::WMemoryWriter wWriter; + + wWriter.write(fmt, args...); + log(lvl, wWriter.c_str()); +} + +template +inline void spdlog::logger::trace(const wchar_t* fmt, const Args&... args) +{ + log(level::trace, fmt, args...); +} + +template +inline void spdlog::logger::debug(const wchar_t* fmt, const Args&... args) +{ + log(level::debug, fmt, args...); +} + +template +inline void spdlog::logger::info(const wchar_t* fmt, const Args&... args) +{ + log(level::info, fmt, args...); +} + + +template +inline void spdlog::logger::warn(const wchar_t* fmt, const Args&... args) +{ + log(level::warn, fmt, args...); +} + +template +inline void spdlog::logger::error(const wchar_t* fmt, const Args&... args) +{ + log(level::err, fmt, args...); +} + +template +inline void spdlog::logger::critical(const wchar_t* fmt, const Args&... args) +{ + log(level::critical, fmt, args...); +} +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index b63ce667..91163efa 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -12,8 +12,9 @@ #include #include #include -#include -#include +#include +#include +#include #include #include @@ -364,6 +365,22 @@ inline std::string filename_to_str(const filename_t& filename) } #endif +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"; + } +} // Return errno string (thread safe) inline std::string errno_str(int err_num) @@ -375,7 +392,7 @@ inline std::string errno_str(int err_num) if(strerror_s(buf, buf_size, err_num) == 0) return std::string(buf); else - return "Unkown error"; + return "Unknown error"; #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \ ((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version @@ -383,10 +400,11 @@ inline std::string errno_str(int err_num) if (strerror_r(err_num, buf, buf_size) == 0) return std::string(buf); else - return "Unkown error"; + return "Unknown error"; #else // gnu version (might not use the given buf, so its retval pointer must be used) - return std::string(strerror_r(err_num, buf, buf_size)); + 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 } @@ -401,6 +419,36 @@ inline int pid() } + +// Detrmine if the terminal supports colors +// Source: https://github.com/agauniyal/rang/ +inline 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; + }); + return result; +#endif +} + + } //os } //details } //spdlog diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 70b9dc80..5d47a04e 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -99,7 +99,7 @@ static const days_array& full_days() static const days_array arr{ { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" } }; return arr; } -class A_formatter:public flag_formatter +class A_formatter SPDLOG_FINAL :public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -128,7 +128,7 @@ static const months_array& full_months() static const months_array arr{ { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" } }; return arr; } -class B_formatter:public flag_formatter +class B_formatter SPDLOG_FINAL :public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -153,7 +153,7 @@ static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v //Date and time representation (Thu Aug 23 15:35:46 2014) -class c_formatter:public flag_formatter +class c_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -164,7 +164,7 @@ class c_formatter:public flag_formatter // year - 2 digit -class C_formatter:public flag_formatter +class C_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -175,7 +175,7 @@ class C_formatter:public flag_formatter // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 -class D_formatter:public flag_formatter +class D_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -185,7 +185,7 @@ class D_formatter:public flag_formatter // year - 4 digit -class Y_formatter:public flag_formatter +class Y_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -194,7 +194,7 @@ class Y_formatter:public flag_formatter }; // month 1-12 -class m_formatter:public flag_formatter +class m_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -203,7 +203,7 @@ class m_formatter:public flag_formatter }; // day of month 1-31 -class d_formatter:public flag_formatter +class d_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -212,7 +212,7 @@ class d_formatter:public flag_formatter }; // hours in 24 format 0-23 -class H_formatter:public flag_formatter +class H_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -221,7 +221,7 @@ class H_formatter:public flag_formatter }; // hours in 12 format 1-12 -class I_formatter:public flag_formatter +class I_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -230,7 +230,7 @@ class I_formatter:public flag_formatter }; // minutes 0-59 -class M_formatter:public flag_formatter +class M_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -239,7 +239,7 @@ class M_formatter:public flag_formatter }; // seconds 0-59 -class S_formatter:public flag_formatter +class S_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -248,7 +248,7 @@ class S_formatter:public flag_formatter }; // milliseconds -class e_formatter:public flag_formatter +class e_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { @@ -259,7 +259,7 @@ class e_formatter:public flag_formatter }; // microseconds -class f_formatter:public flag_formatter +class f_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { @@ -270,7 +270,7 @@ class f_formatter:public flag_formatter }; // nanoseconds -class F_formatter:public flag_formatter +class F_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { @@ -281,7 +281,7 @@ class F_formatter:public flag_formatter }; // AM/PM -class p_formatter:public flag_formatter +class p_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -291,7 +291,7 @@ class p_formatter:public flag_formatter // 12 hour clock 02:55:02 pm -class r_formatter:public flag_formatter +class r_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -300,7 +300,7 @@ class r_formatter:public flag_formatter }; // 24-hour HH:MM time, equivalent to %H:%M -class R_formatter:public flag_formatter +class R_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -309,7 +309,7 @@ class R_formatter:public flag_formatter }; // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S -class T_formatter:public flag_formatter +class T_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -319,12 +319,12 @@ class T_formatter:public flag_formatter // ISO 8601 offset from UTC in timezone (+-HH:MM) -class z_formatter:public flag_formatter +class z_formatter SPDLOG_FINAL:public flag_formatter { public: const std::chrono::seconds cache_refresh = std::chrono::seconds(5); - z_formatter():_last_update(std::chrono::seconds(0)) + z_formatter():_last_update(std::chrono::seconds(0)), _offset_minutes(0) {} z_formatter(const z_formatter&) = delete; z_formatter& operator=(const z_formatter&) = delete; @@ -376,7 +376,7 @@ private: // Thread id -class t_formatter:public flag_formatter +class t_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { @@ -385,7 +385,7 @@ class t_formatter:public flag_formatter }; // Current pid -class pid_formatter:public flag_formatter +class pid_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { @@ -394,7 +394,7 @@ class pid_formatter:public flag_formatter }; -class v_formatter:public flag_formatter +class v_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { @@ -402,7 +402,7 @@ class v_formatter:public flag_formatter } }; -class ch_formatter:public flag_formatter +class ch_formatter SPDLOG_FINAL:public flag_formatter { public: explicit ch_formatter(char ch): _ch(ch) @@ -417,7 +417,7 @@ private: //aggregate user chars to display as is -class aggregate_formatter:public flag_formatter +class aggregate_formatter SPDLOG_FINAL:public flag_formatter { public: aggregate_formatter() @@ -436,7 +436,7 @@ private: // Full info formatter // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v -class full_formatter:public flag_formatter +class full_formatter SPDLOG_FINAL:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { @@ -645,7 +645,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) _formatters.push_back(std::unique_ptr(new details::pid_formatter())); break; - default: //Unkown flag appears as is + default: //Unknown flag appears as is _formatters.push_back(std::unique_ptr(new details::ch_formatter('%'))); _formatters.push_back(std::unique_ptr(new details::ch_formatter(flag))); break; diff --git a/include/spdlog/formatter.h b/include/spdlog/formatter.h index 0ffcec03..639cc7d2 100644 --- a/include/spdlog/formatter.h +++ b/include/spdlog/formatter.h @@ -25,7 +25,7 @@ public: virtual void format(details::log_msg& msg) = 0; }; -class pattern_formatter : public formatter +class pattern_formatter SPDLOG_FINAL : public formatter { public: diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index 58b4841a..af6f93fd 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -43,6 +43,16 @@ public: template void warn(const char* fmt, const Arg1&, const Args&... args); template void error(const char* fmt, const Arg1&, const Args&... args); template void critical(const char* fmt, const Arg1&, const Args&... args); +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + template void log(level::level_enum lvl, const wchar_t* msg); + template void log(level::level_enum lvl, const wchar_t* fmt, const Args&... args); + template void trace(const wchar_t* fmt, const Args&... args); + template void debug(const wchar_t* fmt, const Args&... args); + template void info(const wchar_t* fmt, const Args&... args); + template void warn(const wchar_t* fmt, const Args&... args); + template void error(const wchar_t* fmt, const Args&... args); + template void critical(const wchar_t* fmt, const Args&... args); +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT template void log(level::level_enum lvl, const T&); template void trace(const T&); diff --git a/include/spdlog/sinks/android_sink.h b/include/spdlog/sinks/android_sink.h index d8c97e03..be2d3ad8 100644 --- a/include/spdlog/sinks/android_sink.h +++ b/include/spdlog/sinks/android_sink.h @@ -12,6 +12,12 @@ #include #include #include +#include +#include + +#if !defined(SPDLOG_ANDROID_RETRIES) +#define SPDLOG_ANDROID_RETRIES 2 +#endif namespace spdlog { @@ -25,15 +31,23 @@ namespace sinks class android_sink : public sink { public: - explicit android_sink(const std::string& tag = "spdlog"): _tag(tag) {} + explicit android_sink(const std::string& tag = "spdlog", bool use_raw_msg = false): _tag(tag), _use_raw_msg(use_raw_msg) {} void log(const details::log_msg& msg) override { const android_LogPriority priority = convert_to_android(msg.level); + const char *msg_output = (_use_raw_msg ? msg.raw.c_str() : msg.formatted.c_str()); + // See system/core/liblog/logger_write.c for explanation of return value - const int ret = __android_log_write( - priority, _tag.c_str(), msg.formatted.c_str() - ); + int ret = __android_log_write(priority, _tag.c_str(), msg_output); + int retry_count = 0; + while ((ret == -11/*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) + { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + ret = __android_log_write(priority, _tag.c_str(), msg_output); + retry_count++; + } + if (ret < 0) { throw spdlog_ex("__android_log_write() failed", ret); @@ -67,6 +81,7 @@ private: } std::string _tag; + bool _use_raw_msg; }; } diff --git a/include/spdlog/sinks/ansicolor_sink.h b/include/spdlog/sinks/ansicolor_sink.h index 96e10148..0e5e53c6 100644 --- a/include/spdlog/sinks/ansicolor_sink.h +++ b/include/spdlog/sinks/ansicolor_sink.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -21,7 +22,7 @@ namespace sinks * the output with an ANSI escape sequence color code depending on the severity * of the message. */ -class ansicolor_sink : public sink +class ansicolor_sink SPDLOG_FINAL: public sink { public: ansicolor_sink(sink_ptr wrapped_sink); @@ -36,64 +37,74 @@ public: 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"; + 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"; + 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_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"; + const std::string on_cyan = "\033[46m"; + const std::string on_white = "\033[47m"; protected: + bool is_color_terminal_; sink_ptr sink_; std::map colors_; }; -inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink) +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; + 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; + 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); + // 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() diff --git a/include/spdlog/sinks/base_sink.h b/include/spdlog/sinks/base_sink.h index 7f1a31db..c0a910e0 100644 --- a/include/spdlog/sinks/base_sink.h +++ b/include/spdlog/sinks/base_sink.h @@ -5,8 +5,8 @@ #pragma once // -// base sink templated over a mutex (either dummy or realy) -// concrete implementation should only overrid the _sink_it method. +// base sink templated over a mutex (either dummy or real) +// concrete implementation should only override the _sink_it method. // all locking is taken care of here so no locking needed by the implementers.. // @@ -31,7 +31,7 @@ public: base_sink(const base_sink&) = delete; base_sink& operator=(const base_sink&) = delete; - void log(const details::log_msg& msg) override + void log(const details::log_msg& msg) SPDLOG_FINAL override { std::lock_guard lock(_mutex); _sink_it(msg); diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h index 721a96df..fe40a362 100644 --- a/include/spdlog/sinks/file_sinks.h +++ b/include/spdlog/sinks/file_sinks.h @@ -26,7 +26,7 @@ namespace sinks * Trivial file sink with single file as target */ template -class simple_file_sink : public base_sink < Mutex > +class simple_file_sink SPDLOG_FINAL : public base_sink < Mutex > { public: explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false) @@ -61,7 +61,7 @@ typedef simple_file_sink simple_file_sink_st; * Rotating file sink based on size */ template -class rotating_file_sink : public base_sink < Mutex > +class rotating_file_sink SPDLOG_FINAL : public base_sink < Mutex > { public: rotating_file_sink(const filename_t &base_filename, @@ -177,7 +177,7 @@ struct dateonly_daily_file_name_calculator * Rotating file sink based on date. rotates at midnight */ template -class daily_file_sink :public base_sink < Mutex > +class daily_file_sink SPDLOG_FINAL :public base_sink < Mutex > { public: //create daily file sink which rotates on given time diff --git a/include/spdlog/sinks/stdout_sinks.h b/include/spdlog/sinks/stdout_sinks.h index c05f80dd..4dd52ed8 100644 --- a/include/spdlog/sinks/stdout_sinks.h +++ b/include/spdlog/sinks/stdout_sinks.h @@ -18,7 +18,7 @@ namespace sinks { template -class stdout_sink: public base_sink +class stdout_sink SPDLOG_FINAL : public base_sink { using MyType = stdout_sink; public: @@ -47,7 +47,7 @@ typedef stdout_sink stdout_sink_mt; template -class stderr_sink: public base_sink +class stderr_sink SPDLOG_FINAL : public base_sink { using MyType = stderr_sink; public: diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h index 86f66b9e..c167c716 100644 --- a/include/spdlog/tweakme.h +++ b/include/spdlog/tweakme.h @@ -101,8 +101,22 @@ /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable wchar_t support (convert to utf8) +// +// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT +/////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// // Uncomment to prevent child processes from inheriting log file descriptors // // #define SPDLOG_PREVENT_CHILD_FD /////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to mark some types as final, allowing more optimizations in release +// mode with recent compilers. See GCC's documentation for -Wsuggest-final-types +// for instance. +// +// #define SPDLOG_FINAL final +/////////////////////////////////////////////////////////////////////////////// diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ce275ccb..22329b4e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ find_package(Threads) add_library(catch INTERFACE) target_include_directories(catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -file(GLOB catch_tests LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) +file(GLOB catch_tests LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp *.h *.hpp) add_executable(catch_tests ${catch_tests}) target_link_libraries(catch_tests spdlog ${CMAKE_THREAD_LIBS_INIT})