diff --git a/CMakeLists.txt b/CMakeLists.txt index 3830dfe2..6556144b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,11 +181,12 @@ endif() target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$" - "$") + "$") target_link_libraries(spdlog PUBLIC Threads::Threads) spdlog_enable_warnings(spdlog) -set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}) +set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION + ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}) set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d) if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH) @@ -199,8 +200,9 @@ endif() add_library(spdlog_header_only INTERFACE) add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only) -target_include_directories(spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$" - "$") +target_include_directories( + spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$" + "$") target_link_libraries(spdlog_header_only INTERFACE Threads::Threads) # --------------------------------------------------------------------------------------- @@ -255,10 +257,19 @@ foreach( endif() endforeach() -if(SPDLOG_NO_EXCEPTIONS AND NOT MSVC) - target_compile_options(spdlog PRIVATE -fno-exceptions) +# --------------------------------------------------------------------------------------- +# If exceptions are disabled, disable them in the bundled fmt as well +# --------------------------------------------------------------------------------------- +if(SPDLOG_NO_EXCEPTIONS) + if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) + target_compile_definitions(spdlog PUBLIC FMT_EXCEPTIONS=0) + endif() + if(NOT MSVC) + target_compile_options(spdlog PRIVATE -fno-exceptions) + else() + target_compile_options(spdlog PRIVATE /EHsc) + endif() endif() - # --------------------------------------------------------------------------------------- # Build binaries # --------------------------------------------------------------------------------------- @@ -314,12 +325,12 @@ if(SPDLOG_INSTALL) # --------------------------------------------------------------------------------------- # Install pkg-config file # --------------------------------------------------------------------------------------- - if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") set(PKG_CONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") else() set(PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") endif() - if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") set(PKG_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}") else() set(PKG_CONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") @@ -333,15 +344,11 @@ if(SPDLOG_INSTALL) # --------------------------------------------------------------------------------------- # Install CMake config files # --------------------------------------------------------------------------------------- - export( - TARGETS spdlog - NAMESPACE spdlog:: - FILE "${CMAKE_CURRENT_BINARY_DIR}/${config_targets_file}") + export(TARGETS spdlog NAMESPACE spdlog:: FILE "${CMAKE_CURRENT_BINARY_DIR}/${config_targets_file}") install(EXPORT spdlog DESTINATION ${export_dest_dir} NAMESPACE spdlog:: FILE ${config_targets_file}) include(CMakePackageConfigHelpers) - configure_package_config_file("${project_config_in}" "${project_config_out}" - INSTALL_DESTINATION ${export_dest_dir}) + configure_package_config_file("${project_config_in}" "${project_config_out}" INSTALL_DESTINATION ${export_dest_dir}) write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}") diff --git a/README.md b/README.md index d7434356..35c03422 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Very fast, header-only/compiled, C++ logging library. [![ci](https://github.com/gabime/spdlog/actions/workflows/ci.yml/badge.svg)](https://github.com/gabime/spdlog/actions/workflows/ci.yml)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true&branch=v1.x)](https://ci.appveyor.com/project/gabime/spdlog) [![Release](https://img.shields.io/github/release/gabime/spdlog.svg)](https://github.com/gabime/spdlog/releases/latest) -## Install +## Install #### Header-only version Copy the include [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. @@ -12,14 +12,14 @@ $ git clone https://github.com/gabime/spdlog.git $ cd spdlog && mkdir build && cd build $ cmake .. && make -j ``` - - see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use. + +see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use. ## Platforms - * Linux, FreeBSD, OpenBSD, Solaris, AIX - * Windows (msvc 2013+, cygwin) - * macOS (clang 3.5+) - * Android +* Linux, FreeBSD, OpenBSD, Solaris, AIX +* Windows (msvc 2013+, cygwin) +* macOS (clang 3.5+) +* Android ## Package managers: * Debian: `sudo apt install libspdlog-dev` @@ -44,17 +44,18 @@ $ cmake .. && make -j * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: - * Rotating log files. - * Daily log files. - * Console logging (colors supported). - * syslog. - * Windows event log. - * Windows debugger (```OutputDebugString(..)```). - * Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. + * Rotating log files. + * Daily log files. + * Console logging (colors supported). + * syslog. + * Windows event log. + * Windows debugger (```OutputDebugString(..)```). + * Log to Qt widgets ([example](#log-to-qt-with-nice-colors)). + * Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. * Log filtering - log levels can be modified at runtime as well as compile time. * Support for loading log levels from argv or environment var. * [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand. - + ## Usage samples #### Basic usage @@ -270,7 +271,7 @@ void async_example() ``` --- -#### Asynchronous logger with multi sinks +#### Asynchronous logger with multi sinks ```c++ #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/rotating_file_sink.h" @@ -348,7 +349,7 @@ void err_handler_example() ``` --- -#### syslog +#### syslog ```c++ #include "spdlog/sinks/syslog_sink.h" void syslog_example() @@ -359,7 +360,7 @@ void syslog_example() } ``` --- -#### Android example +#### Android example ```c++ #include "spdlog/sinks/android_sink.h" void android_example() @@ -420,6 +421,22 @@ void replace_default_logger_example() } ``` +--- +#### Log to Qt with nice colors +```c++ +#include "spdlog/spdlog.h" +#include "spdlog/sinks/qt_sinks.h" +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) +{ + setMinimumSize(640, 480); + auto log_widget = new QTextEdit(this); + setCentralWidget(log_widget); + int max_lines = 500; // keep the text widget to max 500 lines. remove old lines if needed. + auto logger = spdlog::qt_color_logger_mt("qt_logger", log_widget, max_lines); + logger->info("Some info message"); +} +``` + --- ## Benchmarks diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index 144f50b8..8003886a 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -17,8 +17,8 @@ if(NOT benchmark_FOUND) message(STATUS "Downloading GoogleBenchmark") include(FetchContent) - # disable tests - set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "") + # disable tests + set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "") # Do not build and run googlebenchmark tests FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0) FetchContent_MakeAvailable(googlebenchmark) diff --git a/bench/latency.cpp b/bench/latency.cpp index f909cf5e..8f002ee1 100644 --- a/bench/latency.cpp +++ b/bench/latency.cpp @@ -116,9 +116,6 @@ int main(int argc, char *argv[]) tracing_null_logger_st->enable_backtrace(64); benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); - - - #ifdef __linux bench_dev_null(); #endif // __linux__ diff --git a/example/example.cpp b/example/example.cpp index 636a1be3..ec31baaa 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -142,7 +142,7 @@ void daily_example() void callback_example() { // Create the logger - auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg &/*msg*/) { + auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg & /*msg*/) { // do what you need to do with msg }); } diff --git a/include/spdlog/async.h b/include/spdlog/async.h index d6e21349..94f9f6d9 100644 --- a/include/spdlog/async.h +++ b/include/spdlog/async.h @@ -35,7 +35,7 @@ template struct async_factory_impl { template - static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) + static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { auto ®istry_inst = details::registry::instance(); @@ -61,13 +61,13 @@ using async_factory = async_factory_impl; using async_factory_nonblock = async_factory_impl; template -inline std::shared_ptr create_async(std::string logger_name, SinkArgs &&... sink_args) +inline std::shared_ptr create_async(std::string logger_name, SinkArgs &&...sink_args) { return async_factory::create(std::move(logger_name), std::forward(sink_args)...); } template -inline std::shared_ptr create_async_nb(std::string logger_name, SinkArgs &&... sink_args) +inline std::shared_ptr create_async_nb(std::string logger_name, SinkArgs &&...sink_args) { return async_factory_nonblock::create(std::move(logger_name), std::forward(sink_args)...); } diff --git a/include/spdlog/async_logger-inl.h b/include/spdlog/async_logger-inl.h index 13da5940..4de8382a 100644 --- a/include/spdlog/async_logger-inl.h +++ b/include/spdlog/async_logger-inl.h @@ -24,37 +24,27 @@ SPDLOG_INLINE spdlog::async_logger::async_logger( {} // send the log message to the thread pool -SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg) +SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); +} +else { - SPDLOG_TRY - { - if (auto pool_ptr = thread_pool_.lock()) - { - pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); - } - else - { - throw_spdlog_ex("async log: thread pool doesn't exist anymore"); - } - } - SPDLOG_LOGGER_CATCH(msg.source) + throw_spdlog_ex("async log: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(msg.source) } // send flush request to the thread pool -SPDLOG_INLINE void spdlog::async_logger::flush_() +SPDLOG_INLINE void spdlog::async_logger::flush_(){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_flush(shared_from_this(), overflow_policy_); +} +else { - SPDLOG_TRY - { - if (auto pool_ptr = thread_pool_.lock()) - { - pool_ptr->post_flush(shared_from_this(), overflow_policy_); - } - else - { - throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); - } - } - SPDLOG_LOGGER_CATCH(source_loc()) + throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(source_loc()) } // diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 8e6b7e1d..a40b129b 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -109,7 +109,8 @@ # define SPDLOG_TRY try # define SPDLOG_THROW(ex) throw(ex) # define SPDLOG_CATCH_STD \ - catch (const std::exception &) {} + catch (const std::exception &) \ + {} #endif #if SPDLOG_CPLUSPLUS > 201703L @@ -246,6 +247,15 @@ using format_string_t = format_string_wrapper, char> template using remove_cvref_t = typename std::remove_cv::type>::type; + +template +# if FMT_VERSION >= 90101 +using fmt_runtime_string = fmt::runtime_format_string; +# else +using fmt_runtime_string = fmt::basic_runtime; +# endif + + // clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here, // in addition, fmt::basic_runtime is only convertible to basic_format_string but not basic_string_view template @@ -439,7 +449,7 @@ template using enable_if_t = typename std::enable_if::type; template -std::unique_ptr make_unique(Args &&... args) +std::unique_ptr make_unique(Args &&...args) { static_assert(!std::is_array::value, "arrays not supported"); return std::unique_ptr(new T(std::forward(args)...)); diff --git a/include/spdlog/details/file_helper-inl.h b/include/spdlog/details/file_helper-inl.h index 3c45d8c0..74c89a87 100644 --- a/include/spdlog/details/file_helper-inl.h +++ b/include/spdlog/details/file_helper-inl.h @@ -92,7 +92,7 @@ SPDLOG_INLINE void file_helper::flush() SPDLOG_INLINE void file_helper::sync() { - if(!os::fsync(fd_)) + if (!os::fsync(fd_)) { throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno); } diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index e1080d05..ea8864ea 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -292,7 +292,8 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) return offset; #else -# if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) +# if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \ + (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris struct helper { @@ -362,15 +363,18 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT // There is no pthread_threadid_np prior to 10.6, and it is not supported on any PPC, // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64. # if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__) - tid = pthread_mach_thread_np(pthread_self()); + tid = pthread_mach_thread_np(pthread_self()); # elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - if (&pthread_threadid_np) { - pthread_threadid_np(nullptr, &tid); - } else { - tid = pthread_mach_thread_np(pthread_self()); - } -# else + if (&pthread_threadid_np) + { pthread_threadid_np(nullptr, &tid); + } + else + { + tid = pthread_mach_thread_np(pthread_self()); + } +# else + pthread_threadid_np(nullptr, &tid); # endif return static_cast(tid); #else // Default to standard C++11 (other Unix) @@ -525,7 +529,7 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) { target.resize(result_size); result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size); - if (result_size > 0) + if (result_size > 0) { assert(result_size == target.size()); return; diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index f55642c1..37b00874 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -111,7 +111,7 @@ SPDLOG_API std::string getenv(const char *field); // Do fsync by FILE objectpointer. // Return true on success. -SPDLOG_API bool fsync(FILE * fp); +SPDLOG_API bool fsync(FILE *fp); } // namespace os } // namespace details diff --git a/include/spdlog/details/synchronous_factory.h b/include/spdlog/details/synchronous_factory.h index 1f729ab9..e1e42268 100644 --- a/include/spdlog/details/synchronous_factory.h +++ b/include/spdlog/details/synchronous_factory.h @@ -13,7 +13,7 @@ class logger; struct synchronous_factory { template - static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) + static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { auto sink = std::make_shared(std::forward(args)...); auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); diff --git a/include/spdlog/details/udp_client-windows.h b/include/spdlog/details/udp_client-windows.h index 7d25f037..10894ee6 100644 --- a/include/spdlog/details/udp_client-windows.h +++ b/include/spdlog/details/udp_client-windows.h @@ -16,9 +16,9 @@ #include #if defined(_MSC_VER) -# pragma comment(lib, "Ws2_32.lib") -# pragma comment(lib, "Mswsock.lib") -# pragma comment(lib, "AdvApi32.lib") +# pragma comment(lib, "Ws2_32.lib") +# pragma comment(lib, "Mswsock.lib") +# pragma comment(lib, "AdvApi32.lib") #endif namespace spdlog { diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index b8269304..4aa5a325 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -86,13 +86,13 @@ public: void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; template - void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&... args) + void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) { log_(loc, lvl, details::to_string_view(fmt.fmt()), std::forward(args)...); } template - void log(level::level_enum lvl, format_string_t fmt, Args &&... args) + void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { log(fmt.loc(), lvl, fmt, std::forward(args)...); } @@ -142,50 +142,50 @@ public: } template - void trace(format_string_t fmt, Args &&... args) + void trace(format_string_t fmt, Args &&...args) { log(level::trace, fmt, std::forward(args)...); } template - void debug(format_string_t fmt, Args &&... args) + void debug(format_string_t fmt, Args &&...args) { log(level::debug, fmt, std::forward(args)...); } template - void info(format_string_t fmt, Args &&... args) + void info(format_string_t fmt, Args &&...args) { log(level::info, fmt, std::forward(args)...); } template - void warn(format_string_t fmt, Args &&... args) + void warn(format_string_t fmt, Args &&...args) { log(level::warn, fmt, std::forward(args)...); } template - void error(format_string_t fmt, Args &&... args) + void error(format_string_t fmt, Args &&...args) { log(level::err, fmt, std::forward(args)...); } template - void critical(format_string_t fmt, Args &&... args) + void critical(format_string_t fmt, Args &&...args) { log(level::critical, fmt, std::forward(args)...); } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template - void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&... args) + void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) { log_(loc, lvl, details::to_string_view(fmt.fmt()), std::forward(args)...); } template - void log(level::level_enum lvl, wformat_string_t fmt, Args &&... args) + void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) { log(fmt.loc(), lvl, fmt, std::forward(args)...); } @@ -226,37 +226,37 @@ public: } template - void trace(wformat_string_t fmt, Args &&... args) + void trace(wformat_string_t fmt, Args &&...args) { log(level::trace, fmt, std::forward(args)...); } template - void debug(wformat_string_t fmt, Args &&... args) + void debug(wformat_string_t fmt, Args &&...args) { log(level::debug, fmt, std::forward(args)...); } template - void info(wformat_string_t fmt, Args &&... args) + void info(wformat_string_t fmt, Args &&...args) { log(level::info, fmt, std::forward(args)...); } template - void warn(wformat_string_t fmt, Args &&... args) + void warn(wformat_string_t fmt, Args &&...args) { log(level::warn, fmt, std::forward(args)...); } template - void error(wformat_string_t fmt, Args &&... args) + void error(wformat_string_t fmt, Args &&...args) { log(level::err, fmt, std::forward(args)...); } template - void critical(wformat_string_t fmt, Args &&... args) + void critical(wformat_string_t fmt, Args &&...args) { log(level::critical, fmt, std::forward(args)...); } @@ -358,7 +358,7 @@ protected: // common implementation for after templated public api has been resolved template - void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&... args) + void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args) { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); @@ -370,7 +370,7 @@ protected: { memory_buf_t buf; #ifdef SPDLOG_USE_STD_FORMAT - fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(std::forward(args)...)); + fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...)); #else fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...)); #endif @@ -383,7 +383,7 @@ protected: #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template - void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&... args) + void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args) { bool log_enabled = should_log(lvl); bool traceback_enabled = tracer_.enabled(); @@ -395,8 +395,7 @@ protected: { // format to wmemory_buffer and convert to utf8 wmemory_buf_t wbuf; - fmt_lib::vformat_to( - std::back_inserter(wbuf), fmt, fmt_lib::make_format_args(std::forward(args)...)); + fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, fmt_lib::make_format_args(args...)); memory_buf_t buf; details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf); diff --git a/include/spdlog/pattern_formatter.h b/include/spdlog/pattern_formatter.h index acf1c536..4c87b21e 100644 --- a/include/spdlog/pattern_formatter.h +++ b/include/spdlog/pattern_formatter.h @@ -92,7 +92,7 @@ public: void format(const details::log_msg &msg, memory_buf_t &dest) override; template - pattern_formatter &add_flag(char flag, Args &&... args) + pattern_formatter &add_flag(char flag, Args &&...args) { custom_handlers_[flag] = details::make_unique(std::forward(args)...); return *this; diff --git a/include/spdlog/sinks/ansicolor_sink-inl.h b/include/spdlog/sinks/ansicolor_sink-inl.h index b5848f2d..c924fc5b 100644 --- a/include/spdlog/sinks/ansicolor_sink-inl.h +++ b/include/spdlog/sinks/ansicolor_sink-inl.h @@ -21,20 +21,20 @@ SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, co { set_color_mode(mode); - colors_[level::trace] = to_string_(white); - colors_[level::debug] = to_string_(cyan); - colors_[level::info] = to_string_(green); - colors_[level::warn] = to_string_(yellow_bold); - colors_[level::err] = to_string_(red_bold); - colors_[level::critical] = to_string_(bold_on_red); - colors_[level::off] = to_string_(reset); + colors_.at(level::trace) = to_string_(white); + colors_.at(level::debug) = to_string_(cyan); + colors_.at(level::info) = to_string_(green); + colors_.at(level::warn) = to_string_(yellow_bold); + colors_.at(level::err) = to_string_(red_bold); + colors_.at(level::critical) = to_string_(bold_on_red); + colors_.at(level::off) = to_string_(reset); } template SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, string_view_t color) { std::lock_guard lock(mutex_); - colors_[static_cast(color_level)] = to_string_(color); + colors_.at(static_cast(color_level)) = to_string_(color); } template @@ -52,7 +52,7 @@ SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg // before color range print_range_(formatted, 0, msg.color_range_start); // in color range - print_ccode_(colors_[static_cast(msg.level)]); + print_ccode_(colors_.at(static_cast(msg.level))); print_range_(formatted, msg.color_range_start, msg.color_range_end); print_ccode_(reset); // after color range diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index 25abb02b..0770380c 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -50,12 +50,12 @@ struct daily_filename_format_calculator static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) { #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - std::wstringstream stream; + std::wstringstream stream; #else - std::stringstream stream; + std::stringstream stream; #endif - stream << std::put_time(&now_tm, file_path.c_str()); - return stream.str(); + stream << std::put_time(&now_tm, file_path.c_str()); + return stream.str(); } }; diff --git a/include/spdlog/sinks/kafka_sink.h b/include/spdlog/sinks/kafka_sink.h index 3c0680ef..ce740efc 100644 --- a/include/spdlog/sinks/kafka_sink.h +++ b/include/spdlog/sinks/kafka_sink.h @@ -28,12 +28,12 @@ struct kafka_sink_config { std::string server_addr; std::string produce_topic; - int32_t flush_timeout_ms = 1000; + int32_t flush_timeout_ms = 1000; kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000) - : server_addr{std::move(addr)} - ,produce_topic{std::move(topic)} - ,flush_timeout_ms(flush_timeout_ms) + : server_addr{std::move(addr)} + , produce_topic{std::move(topic)} + , flush_timeout_ms(flush_timeout_ms) {} }; @@ -42,8 +42,8 @@ class kafka_sink : public base_sink { public: kafka_sink(kafka_sink_config config) - : config_{std::move(config)} - { + : config_{std::move(config)} + { try { std::string errstr; @@ -75,7 +75,7 @@ public: { throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what())); } - } + } ~kafka_sink() { @@ -85,7 +85,7 @@ public: protected: void sink_it_(const details::log_msg &msg) override { - producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, (void *)msg.payload.data(), msg.payload.size(), NULL, NULL); + producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, (void *)msg.payload.data(), msg.payload.size(), NULL, NULL); } void flush_() override @@ -104,7 +104,7 @@ private: using kafka_sink_mt = kafka_sink; using kafka_sink_st = kafka_sink; -} // namespace sinks +} // namespace sinks template inline std::shared_ptr kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) @@ -121,13 +121,13 @@ inline std::shared_ptr kafka_logger_st(const std::string &logger_name, s template inline std::shared_ptr kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config) { - return Factory::template create(logger_name, config); + return Factory::template create(logger_name, config); } template inline std::shared_ptr kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config) { - return Factory::template create(logger_name, config); + return Factory::template create(logger_name, config); } -} // namespace spdlog +} // namespace spdlog diff --git a/include/spdlog/sinks/msvc_sink.h b/include/spdlog/sinks/msvc_sink.h index 34d5f34e..bf68ae88 100644 --- a/include/spdlog/sinks/msvc_sink.h +++ b/include/spdlog/sinks/msvc_sink.h @@ -3,7 +3,6 @@ #pragma once - #if defined(_WIN32) # include @@ -16,11 +15,11 @@ # include // Avoid including windows.h (https://stackoverflow.com/a/30741042) -#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString); -#else +# else extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); -#endif +# endif extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace spdlog { @@ -46,13 +45,13 @@ protected: memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); formatted.push_back('\0'); // add a null terminator for OutputDebugString -#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) wmemory_buf_t wformatted; details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); OutputDebugStringW(wformatted.data()); -#else +# else OutputDebugStringA(formatted.data()); -#endif +# endif } void flush_() override {} diff --git a/include/spdlog/sinks/qt_sinks.h b/include/spdlog/sinks/qt_sinks.h index 31b49c60..14a95bcc 100644 --- a/include/spdlog/sinks/qt_sinks.h +++ b/include/spdlog/sinks/qt_sinks.h @@ -7,11 +7,16 @@ // Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... // etc) Building and using requires Qt library. // +// Warning: the qt_sink won't be notified if the target widget is destroyed. +// If the widget's lifetime can be shorter than the logger's one, you should provide some permanent QObject, +// and then use a standard signal/slot. +// #include "spdlog/common.h" #include "spdlog/details/log_msg.h" #include "spdlog/details/synchronous_factory.h" #include "spdlog/sinks/base_sink.h" +#include #include #include @@ -53,15 +58,185 @@ private: std::string meta_method_; }; +// QT color sink to QTextEdit. +// Color location is determined by the sink log pattern like in the rest of spdlog sinks. +// Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). +// max_lines is the maximum number of lines that the sink will hold before removing the oldest lines. +// Note: Only ascii (latin1) is supported by this sink. + template + class qt_color_sink : public base_sink + { + public: + qt_color_sink(QTextEdit *qt_text_edit, int max_lines) + : qt_text_edit_(qt_text_edit), max_lines_(max_lines) + { + if (!qt_text_edit_) + { + throw_spdlog_ex("qt_color_text_sink: text_edit is null"); + } + + default_color_ = qt_text_edit_->currentCharFormat(); + // set colors + QTextCharFormat format; + // trace + format.setForeground(Qt::gray); + colors_.at(level::trace) = format; + // debug + format.setForeground(Qt::cyan); + colors_.at(level::debug) = format; + // info + format.setForeground(Qt::green); + colors_.at(level::info) = format; + // warn + format.setForeground(Qt::yellow); + colors_.at(level::warn) = format; + // err + format.setForeground(Qt::red); + colors_.at(level::err) = format; + // critical + format.setForeground(Qt::white); + format.setBackground(Qt::red); + colors_.at(level::critical) = format; + } + + ~qt_color_sink() + { + flush_(); + } + + void set_default_color(QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + default_color_ = format; + } + + void set_level_color(level::level_enum color_level, QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + colors_.at(static_cast(color_level)) = format; + } + + QTextCharFormat &get_level_color(level::level_enum color_level) + { + std::lock_guard lock(base_sink::mutex_); + return colors_.at(static_cast(color_level)); + } + + QTextCharFormat &get_default_color() + { + std::lock_guard lock(base_sink::mutex_); + return default_color_; + } + + protected: + struct invoke_params + { + invoke_params(int max_lines, QTextEdit *q_text_edit, QString payload, QTextCharFormat default_color, + QTextCharFormat level_color, int color_range_start, int color_range_end) + : max_lines(max_lines), + q_text_edit(q_text_edit), + payload(std::move(payload)), + default_color(default_color), + level_color(level_color), + color_range_start(color_range_start), + color_range_end(color_range_end) + { + } + int max_lines; + QTextEdit *q_text_edit; + QString payload; + QTextCharFormat default_color; + QTextCharFormat level_color; + int color_range_start; + int color_range_end; + }; + void sink_it_(const details::log_msg &msg) override + { + + using this_type = qt_color_sink; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + // apply the color to the color range in the formatted message. + auto payload = QString::fromLatin1(str.data(), static_cast(str.size())); + + invoke_params params { + max_lines_, // max lines + qt_text_edit_, // text edit to append to + std::move(payload), // text to append + default_color_, // default color + colors_.at(msg.level), // color to apply + msg.color_range_start, // color range start + msg.color_range_end}; // color range end + + QMetaObject::invokeMethod( + qt_text_edit_, + [params]() {invoke_method_(params);}, + Qt::AutoConnection); + + } + + void flush_() override {} + + // Add colored text to the text edit widget. This method is invoked in the GUI thread. + // It is a static method to ensure that it is handled correctly even if the sink is destroyed prematurely + // before it is invoked. + + static void invoke_method_(invoke_params params) + { + auto *document = params.q_text_edit->document(); + QTextCursor cursor(document); + + // remove first blocks if number of blocks exceeds max_lines + while(document->blockCount() > params.max_lines) + { + cursor.select(QTextCursor::BlockUnderCursor); + cursor.removeSelectedText(); + cursor.deleteChar(); // delete the newline after the block + } + + cursor.movePosition(QTextCursor::End); + cursor.setCharFormat(params.default_color); + + // if color range not specified or not not valid, just append the text with default color + if(params.color_range_end <= params.color_range_start) + { + cursor.insertText(params.payload); + return; + } + + // insert the text before the color range + cursor.insertText(params.payload.left(params.color_range_start)); + + // insert the colorized text + cursor.setCharFormat(params.level_color); + cursor.insertText(params.payload.mid(params.color_range_start, params.color_range_end - params.color_range_start)); + + // insert the text after the color range with default format + cursor.setCharFormat(params.default_color); + cursor.insertText(params.payload.mid(params.color_range_end)); + } + + QTextEdit *qt_text_edit_; + int max_lines_; + QTextCharFormat default_color_; + std::array colors_; + }; + #include "spdlog/details/null_mutex.h" #include using qt_sink_mt = qt_sink; -using qt_sink_st = qt_sink; +using qt_sink_st = qt_sink; +using qt_color_sink_mt = qt_color_sink; +using qt_color_sink_st = qt_color_sink; } // namespace sinks // // Factory functions // + +// log to QTextEdit template inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") { @@ -74,6 +249,7 @@ inline std::shared_ptr qt_logger_st(const std::string &logger_name, QTex return Factory::template create(logger_name, qt_object, meta_method); } +// log to QPlainTextEdit template inline std::shared_ptr qt_logger_mt( const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") @@ -87,7 +263,7 @@ inline std::shared_ptr qt_logger_st( { return Factory::template create(logger_name, qt_object, meta_method); } - +// log to QObject template inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) { @@ -99,4 +275,18 @@ inline std::shared_ptr qt_logger_st(const std::string &logger_name, QObj { return Factory::template create(logger_name, qt_object, meta_method); } + +// log to QTextEdit with colorize output +template +inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) +{ + return Factory::template create(logger_name, qt_text_edit, max_lines); +} + +template +inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) +{ + return Factory::template create(logger_name, qt_text_edit, max_lines); +} + } // namespace spdlog diff --git a/include/spdlog/sinks/stdout_sinks-inl.h b/include/spdlog/sinks/stdout_sinks-inl.h index 9e8e6ddf..c1754370 100644 --- a/include/spdlog/sinks/stdout_sinks-inl.h +++ b/include/spdlog/sinks/stdout_sinks-inl.h @@ -72,7 +72,7 @@ SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &m memory_buf_t formatted; formatter_->format(msg, formatted); ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); -#endif // WIN32 +#endif // WIN32 ::fflush(file_); // flush every line to terminal } diff --git a/include/spdlog/sinks/win_eventlog_sink.h b/include/spdlog/sinks/win_eventlog_sink.h index def4b135..d23d00a8 100644 --- a/include/spdlog/sinks/win_eventlog_sink.h +++ b/include/spdlog/sinks/win_eventlog_sink.h @@ -241,12 +241,12 @@ protected: details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); LPCWSTR lp_wstr = buf.data(); - succeeded = static_cast(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, - current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); + succeeded = static_cast(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); #else LPCSTR lp_str = formatted.data(); - succeeded = static_cast(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, - current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); + succeeded = static_cast(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); #endif if (!succeeded) diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 25c21dae..70bcbe23 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -32,7 +32,7 @@ using default_factory = synchronous_factory; // Example: // spdlog::create("logger_name", "dailylog_filename", 11, 59); template -inline std::shared_ptr create(std::string logger_name, SinkArgs &&... sink_args) +inline std::shared_ptr create(std::string logger_name, SinkArgs &&...sink_args) { return default_factory::create(std::move(logger_name), std::forward(sink_args)...); } @@ -142,49 +142,49 @@ SPDLOG_API void set_default_logger(std::shared_ptr default_logge SPDLOG_API void apply_logger_env_levels(std::shared_ptr logger); template -inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, Args &&... args) +inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, Args &&...args) { default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); } template -inline void log(level::level_enum lvl, format_string_t fmt, Args &&... args) +inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); } template -inline void trace(format_string_t fmt, Args &&... args) +inline void trace(format_string_t fmt, Args &&...args) { default_logger_raw()->trace(fmt, std::forward(args)...); } template -inline void debug(format_string_t fmt, Args &&... args) +inline void debug(format_string_t fmt, Args &&...args) { default_logger_raw()->debug(fmt, std::forward(args)...); } template -inline void info(format_string_t fmt, Args &&... args) +inline void info(format_string_t fmt, Args &&...args) { default_logger_raw()->info(fmt, std::forward(args)...); } template -inline void warn(format_string_t fmt, Args &&... args) +inline void warn(format_string_t fmt, Args &&...args) { default_logger_raw()->warn(fmt, std::forward(args)...); } template -inline void error(format_string_t fmt, Args &&... args) +inline void error(format_string_t fmt, Args &&...args) { default_logger_raw()->error(fmt, std::forward(args)...); } template -inline void critical(format_string_t fmt, Args &&... args) +inline void critical(format_string_t fmt, Args &&...args) { default_logger_raw()->critical(fmt, std::forward(args)...); } @@ -203,49 +203,49 @@ inline void log(level::level_enum lvl, const T &msg) #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template -inline void log(source_loc source, level::level_enum lvl, wformat_string_t fmt, Args &&... args) +inline void log(source_loc source, level::level_enum lvl, wformat_string_t fmt, Args &&...args) { default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); } template -inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&... args) +inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); } template -inline void trace(wformat_string_t fmt, Args &&... args) +inline void trace(wformat_string_t fmt, Args &&...args) { default_logger_raw()->trace(fmt, std::forward(args)...); } template -inline void debug(wformat_string_t fmt, Args &&... args) +inline void debug(wformat_string_t fmt, Args &&...args) { default_logger_raw()->debug(fmt, std::forward(args)...); } template -inline void info(wformat_string_t fmt, Args &&... args) +inline void info(wformat_string_t fmt, Args &&...args) { default_logger_raw()->info(fmt, std::forward(args)...); } template -inline void warn(wformat_string_t fmt, Args &&... args) +inline void warn(wformat_string_t fmt, Args &&...args) { default_logger_raw()->warn(fmt, std::forward(args)...); } template -inline void error(wformat_string_t fmt, Args &&... args) +inline void error(wformat_string_t fmt, Args &&...args) { default_logger_raw()->error(fmt, std::forward(args)...); } template -inline void critical(wformat_string_t fmt, Args &&... args) +inline void critical(wformat_string_t fmt, Args &&...args) { default_logger_raw()->critical(fmt, std::forward(args)...); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 131b22f8..942ec519 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,16 +14,12 @@ if(PkgConfig_FOUND) endif() find_package(Catch2 3 QUIET) -if (Catch2_FOUND) +if(Catch2_FOUND) message(STATUS "Packaged version of Catch will be used.") else() message(STATUS "Bundled version of Catch will be downloaded and used.") include(FetchContent) - FetchContent_Declare( - Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.3.2 - ) + FetchContent_Declare(Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.3.2) FetchContent_MakeAvailable(Catch2) endif() diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp index a698c47b..78032482 100644 --- a/tests/test_errors.cpp +++ b/tests/test_errors.cpp @@ -1,6 +1,6 @@ /* -* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE -*/ + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ #include "includes.h" #include @@ -11,114 +11,114 @@ class failing_sink : public spdlog::sinks::base_sink { protected: - void sink_it_(const spdlog::details::log_msg &) final - { - throw std::runtime_error("some error happened during log"); - } + void sink_it_(const spdlog::details::log_msg &) final + { + throw std::runtime_error("some error happened during log"); + } - void flush_() final - { - throw std::runtime_error("some error happened during flush"); - } + void flush_() final + { + throw std::runtime_error("some error happened during flush"); + } }; -struct custom_ex {}; +struct custom_ex +{}; #if !defined(SPDLOG_USE_STD_FORMAT) // std formt doesn't fully support tuntime strings TEST_CASE("default_error_handler", "[errors]") { - prepare_logdir(); - spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); - auto logger = spdlog::create("test-error", filename, true); - logger->set_pattern("%v"); - logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1); - logger->info("Test message {}", 2); - logger->flush(); - using spdlog::details::os::default_eol; - REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol)); - REQUIRE(count_lines(SIMPLE_LOG) == 1); + auto logger = spdlog::create("test-error", filename, true); + logger->set_pattern("%v"); + logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1); + logger->info("Test message {}", 2); + logger->flush(); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol)); + REQUIRE(count_lines(SIMPLE_LOG) == 1); } - TEST_CASE("custom_error_handler", "[errors]") { - prepare_logdir(); - spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); - auto logger = spdlog::create("logger", filename, true); - logger->flush_on(spdlog::level::info); - logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); - logger->info("Good message #1"); + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); + auto logger = spdlog::create("logger", filename, true); + logger->flush_on(spdlog::level::info); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + logger->info("Good message #1"); - REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); - logger->info("Good message #2"); - require_message_count(SIMPLE_LOG, 2); + REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); + logger->info("Good message #2"); + require_message_count(SIMPLE_LOG, 2); } #endif TEST_CASE("default_error_handler2", "[errors]") { - spdlog::drop_all(); - auto logger = spdlog::create("failed_logger"); - logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); - REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); + spdlog::drop_all(); + auto logger = spdlog::create("failed_logger"); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); } TEST_CASE("flush_error_handler", "[errors]") { - spdlog::drop_all(); - auto logger = spdlog::create("failed_logger"); - logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); - REQUIRE_THROWS_AS(logger->flush(), custom_ex); + spdlog::drop_all(); + auto logger = spdlog::create("failed_logger"); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + REQUIRE_THROWS_AS(logger->flush(), custom_ex); } #if !defined(SPDLOG_USE_STD_FORMAT) TEST_CASE("async_error_handler", "[errors]") { - prepare_logdir(); - std::string err_msg("log failed with some msg"); + prepare_logdir(); + std::string err_msg("log failed with some msg"); - spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG); - { - spdlog::init_thread_pool(128, 1); - auto logger = spdlog::create_async("logger", filename, true); - logger->set_error_handler([=](const std::string &) { - std::ofstream ofs("test_logs/custom_err.txt"); - if (!ofs) - { - throw std::runtime_error("Failed open test_logs/custom_err.txt"); - } - ofs << err_msg; - }); - logger->info("Good message #1"); - logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"); - logger->info("Good message #2"); - spdlog::drop("logger"); // force logger to drain the queue and shutdown - } - spdlog::init_thread_pool(128, 1); - require_message_count(SIMPLE_ASYNC_LOG, 2); - REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG); + { + spdlog::init_thread_pool(128, 1); + auto logger = spdlog::create_async("logger", filename, true); + logger->set_error_handler([=](const std::string &) { + std::ofstream ofs("test_logs/custom_err.txt"); + if (!ofs) + { + throw std::runtime_error("Failed open test_logs/custom_err.txt"); + } + ofs << err_msg; + }); + logger->info("Good message #1"); + logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"); + logger->info("Good message #2"); + spdlog::drop("logger"); // force logger to drain the queue and shutdown + } + spdlog::init_thread_pool(128, 1); + require_message_count(SIMPLE_ASYNC_LOG, 2); + REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); } #endif // Make sure async error handler is executed TEST_CASE("async_error_handler2", "[errors]") { - prepare_logdir(); - std::string err_msg("This is async handler error message"); - { - spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs")); - spdlog::init_thread_pool(128, 1); - auto logger = spdlog::create_async("failed_logger"); - logger->set_error_handler([=](const std::string &) { - std::ofstream ofs("test_logs/custom_err2.txt"); - if (!ofs) - throw std::runtime_error("Failed open test_logs/custom_err2.txt"); - ofs << err_msg; - }); - logger->info("Hello failure"); - spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown - } + prepare_logdir(); + std::string err_msg("This is async handler error message"); + { + spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs")); + spdlog::init_thread_pool(128, 1); + auto logger = spdlog::create_async("failed_logger"); + logger->set_error_handler([=](const std::string &) { + std::ofstream ofs("test_logs/custom_err2.txt"); + if (!ofs) + throw std::runtime_error("Failed open test_logs/custom_err2.txt"); + ofs << err_msg; + }); + logger->info("Hello failure"); + spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown + } - spdlog::init_thread_pool(128, 1); - REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg); + spdlog::init_thread_pool(128, 1); + REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg); } diff --git a/tests/test_pattern_formatter.cpp b/tests/test_pattern_formatter.cpp index b89f51d4..bafea884 100644 --- a/tests/test_pattern_formatter.cpp +++ b/tests/test_pattern_formatter.cpp @@ -6,7 +6,7 @@ using spdlog::details::to_string_view; // log to str and return it template -static std::string log_to_str(const std::string &msg, const Args &... args) +static std::string log_to_str(const std::string &msg, const Args &...args) { std::ostringstream oss; auto oss_sink = std::make_shared(oss);