Merge branch 'v1.x' into feature-source_location

pull/2690/head
M. Galib Uludag 2 years ago committed by GitHub
commit 7b378662cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -181,11 +181,12 @@ endif()
target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB)
target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>" target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>") "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(spdlog PUBLIC Threads::Threads) target_link_libraries(spdlog PUBLIC Threads::Threads)
spdlog_enable_warnings(spdlog) 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) set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d)
if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH) if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH)
@ -199,8 +200,9 @@ endif()
add_library(spdlog_header_only INTERFACE) add_library(spdlog_header_only INTERFACE)
add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only) add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only)
target_include_directories(spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>" target_include_directories(
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>") spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(spdlog_header_only INTERFACE Threads::Threads) target_link_libraries(spdlog_header_only INTERFACE Threads::Threads)
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
@ -255,10 +257,19 @@ foreach(
endif() endif()
endforeach() 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() endif()
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Build binaries # Build binaries
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
@ -314,12 +325,12 @@ if(SPDLOG_INSTALL)
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Install pkg-config file # Install pkg-config file
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(PKG_CONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") set(PKG_CONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
else() else()
set(PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") set(PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif() endif()
if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(PKG_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}") set(PKG_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
else() else()
set(PKG_CONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") set(PKG_CONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
@ -333,15 +344,11 @@ if(SPDLOG_INSTALL)
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Install CMake config files # Install CMake config files
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
export( export(TARGETS spdlog NAMESPACE spdlog:: FILE "${CMAKE_CURRENT_BINARY_DIR}/${config_targets_file}")
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}) install(EXPORT spdlog DESTINATION ${export_dest_dir} NAMESPACE spdlog:: FILE ${config_targets_file})
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
configure_package_config_file("${project_config_in}" "${project_config_out}" configure_package_config_file("${project_config_in}" "${project_config_out}" INSTALL_DESTINATION ${export_dest_dir})
INSTALL_DESTINATION ${export_dest_dir})
write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}") install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}")

@ -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)&nbsp; [![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) 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)&nbsp; [![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 #### 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. 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 $ cd spdlog && mkdir build && cd build
$ cmake .. && make -j $ 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 ## Platforms
* Linux, FreeBSD, OpenBSD, Solaris, AIX * Linux, FreeBSD, OpenBSD, Solaris, AIX
* Windows (msvc 2013+, cygwin) * Windows (msvc 2013+, cygwin)
* macOS (clang 3.5+) * macOS (clang 3.5+)
* Android * Android
## Package managers: ## Package managers:
* Debian: `sudo apt install libspdlog-dev` * Debian: `sudo apt install libspdlog-dev`
@ -44,17 +44,18 @@ $ cmake .. && make -j
* [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting.
* Multi/Single threaded loggers. * Multi/Single threaded loggers.
* Various log targets: * Various log targets:
* Rotating log files. * Rotating log files.
* Daily log files. * Daily log files.
* Console logging (colors supported). * Console logging (colors supported).
* syslog. * syslog.
* Windows event log. * Windows event log.
* Windows debugger (```OutputDebugString(..)```). * Windows debugger (```OutputDebugString(..)```).
* Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. * 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. * Log filtering - log levels can be modified at runtime as well as compile time.
* Support for loading log levels from argv or environment var. * 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. * [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand.
## Usage samples ## Usage samples
#### Basic usage #### Basic usage
@ -270,7 +271,7 @@ void async_example()
``` ```
--- ---
#### Asynchronous logger with multi sinks #### Asynchronous logger with multi sinks
```c++ ```c++
#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h" #include "spdlog/sinks/rotating_file_sink.h"
@ -348,7 +349,7 @@ void err_handler_example()
``` ```
--- ---
#### syslog #### syslog
```c++ ```c++
#include "spdlog/sinks/syslog_sink.h" #include "spdlog/sinks/syslog_sink.h"
void syslog_example() void syslog_example()
@ -359,7 +360,7 @@ void syslog_example()
} }
``` ```
--- ---
#### Android example #### Android example
```c++ ```c++
#include "spdlog/sinks/android_sink.h" #include "spdlog/sinks/android_sink.h"
void android_example() 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 ## Benchmarks

@ -17,8 +17,8 @@ if(NOT benchmark_FOUND)
message(STATUS "Downloading GoogleBenchmark") message(STATUS "Downloading GoogleBenchmark")
include(FetchContent) include(FetchContent)
# disable tests # disable tests
set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "") set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "")
# Do not build and run googlebenchmark tests # Do not build and run googlebenchmark tests
FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0) FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0)
FetchContent_MakeAvailable(googlebenchmark) FetchContent_MakeAvailable(googlebenchmark)

@ -116,9 +116,6 @@ int main(int argc, char *argv[])
tracing_null_logger_st->enable_backtrace(64); tracing_null_logger_st->enable_backtrace(64);
benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st);
#ifdef __linux #ifdef __linux
bench_dev_null(); bench_dev_null();
#endif // __linux__ #endif // __linux__

@ -142,7 +142,7 @@ void daily_example()
void callback_example() void callback_example()
{ {
// Create the logger // 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 // do what you need to do with msg
}); });
} }

@ -35,7 +35,7 @@ template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl struct async_factory_impl
{ {
template<typename Sink, typename... SinkArgs> template<typename Sink, typename... SinkArgs>
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args) static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args)
{ {
auto &registry_inst = details::registry::instance(); auto &registry_inst = details::registry::instance();
@ -61,13 +61,13 @@ using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>; using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
template<typename Sink, typename... SinkArgs> template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args) inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&...sink_args)
{ {
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
} }
template<typename Sink, typename... SinkArgs> template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&... sink_args) inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&...sink_args)
{ {
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
} }

@ -24,37 +24,27 @@ SPDLOG_INLINE spdlog::async_logger::async_logger(
{} {}
// send the log message to the thread pool // 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 throw_spdlog_ex("async log: thread pool doesn't exist anymore");
{ }
if (auto pool_ptr = thread_pool_.lock()) }
{ SPDLOG_LOGGER_CATCH(msg.source)
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)
} }
// send flush request to the thread pool // 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 throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
{ }
if (auto pool_ptr = thread_pool_.lock()) }
{ SPDLOG_LOGGER_CATCH(source_loc())
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())
} }
// //

@ -109,7 +109,8 @@
# define SPDLOG_TRY try # define SPDLOG_TRY try
# define SPDLOG_THROW(ex) throw(ex) # define SPDLOG_THROW(ex) throw(ex)
# define SPDLOG_CATCH_STD \ # define SPDLOG_CATCH_STD \
catch (const std::exception &) {} catch (const std::exception &) \
{}
#endif #endif
#if SPDLOG_CPLUSPLUS > 201703L #if SPDLOG_CPLUSPLUS > 201703L
@ -246,6 +247,15 @@ using format_string_t = format_string_wrapper<fmt::format_string<Args...>, char>
template<class T> template<class T>
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<typename Char>
# if FMT_VERSION >= 90101
using fmt_runtime_string = fmt::runtime_format_string<Char>;
# else
using fmt_runtime_string = fmt::basic_runtime<Char>;
# endif
// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here, // 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<Char> is only convertible to basic_format_string<Char> but not basic_string_view<Char> // in addition, fmt::basic_runtime<Char> is only convertible to basic_format_string<Char> but not basic_string_view<Char>
template<class T, class Char = char> template<class T, class Char = char>
@ -439,7 +449,7 @@ template<bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type; using enable_if_t = typename std::enable_if<B, T>::type;
template<typename T, typename... Args> template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args) std::unique_ptr<T> make_unique(Args &&...args)
{ {
static_assert(!std::is_array<T>::value, "arrays not supported"); static_assert(!std::is_array<T>::value, "arrays not supported");
return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); return std::unique_ptr<T>(new T(std::forward<Args>(args)...));

@ -92,7 +92,7 @@ SPDLOG_INLINE void file_helper::flush()
SPDLOG_INLINE void file_helper::sync() 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); throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno);
} }

@ -292,7 +292,8 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
return offset; return offset;
#else #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 // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
struct helper 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, // 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. // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
# if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__) # 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 # elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
if (&pthread_threadid_np) { if (&pthread_threadid_np)
pthread_threadid_np(nullptr, &tid); {
} else {
tid = pthread_mach_thread_np(pthread_self());
}
# else
pthread_threadid_np(nullptr, &tid); pthread_threadid_np(nullptr, &tid);
}
else
{
tid = pthread_mach_thread_np(pthread_self());
}
# else
pthread_threadid_np(nullptr, &tid);
# endif # endif
return static_cast<size_t>(tid); return static_cast<size_t>(tid);
#else // Default to standard C++11 (other Unix) #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); target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), 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()); assert(result_size == target.size());
return; return;

@ -111,7 +111,7 @@ SPDLOG_API std::string getenv(const char *field);
// Do fsync by FILE objectpointer. // Do fsync by FILE objectpointer.
// Return true on success. // Return true on success.
SPDLOG_API bool fsync(FILE * fp); SPDLOG_API bool fsync(FILE *fp);
} // namespace os } // namespace os
} // namespace details } // namespace details

@ -13,7 +13,7 @@ class logger;
struct synchronous_factory struct synchronous_factory
{ {
template<typename Sink, typename... SinkArgs> template<typename Sink, typename... SinkArgs>
static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args) static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&...args)
{ {
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink)); auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));

@ -16,9 +16,9 @@
#include <string> #include <string>
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma comment(lib, "Ws2_32.lib") # pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Mswsock.lib") # pragma comment(lib, "Mswsock.lib")
# pragma comment(lib, "AdvApi32.lib") # pragma comment(lib, "AdvApi32.lib")
#endif #endif
namespace spdlog { namespace spdlog {

@ -86,13 +86,13 @@ public:
void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
template<typename... Args> template<typename... Args>
void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{ {
log_(loc, lvl, details::to_string_view(fmt.fmt()), std::forward<Args>(args)...); log_(loc, lvl, details::to_string_view(fmt.fmt()), std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{ {
log(fmt.loc(), lvl, fmt, std::forward<Args>(args)...); log(fmt.loc(), lvl, fmt, std::forward<Args>(args)...);
} }
@ -142,50 +142,50 @@ public:
} }
template<typename... Args> template<typename... Args>
void trace(format_string_t<Args...> fmt, Args &&... args) void trace(format_string_t<Args...> fmt, Args &&...args)
{ {
log(level::trace, fmt, std::forward<Args>(args)...); log(level::trace, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void debug(format_string_t<Args...> fmt, Args &&... args) void debug(format_string_t<Args...> fmt, Args &&...args)
{ {
log(level::debug, fmt, std::forward<Args>(args)...); log(level::debug, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void info(format_string_t<Args...> fmt, Args &&... args) void info(format_string_t<Args...> fmt, Args &&...args)
{ {
log(level::info, fmt, std::forward<Args>(args)...); log(level::info, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void warn(format_string_t<Args...> fmt, Args &&... args) void warn(format_string_t<Args...> fmt, Args &&...args)
{ {
log(level::warn, fmt, std::forward<Args>(args)...); log(level::warn, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void error(format_string_t<Args...> fmt, Args &&... args) void error(format_string_t<Args...> fmt, Args &&...args)
{ {
log(level::err, fmt, std::forward<Args>(args)...); log(level::err, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void critical(format_string_t<Args...> fmt, Args &&... args) void critical(format_string_t<Args...> fmt, Args &&...args)
{ {
log(level::critical, fmt, std::forward<Args>(args)...); log(level::critical, fmt, std::forward<Args>(args)...);
} }
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args> template<typename... Args>
void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args) void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{ {
log_(loc, lvl, details::to_string_view(fmt.fmt()), std::forward<Args>(args)...); log_(loc, lvl, details::to_string_view(fmt.fmt()), std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args) void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(fmt.loc(), lvl, fmt, std::forward<Args>(args)...); log(fmt.loc(), lvl, fmt, std::forward<Args>(args)...);
} }
@ -226,37 +226,37 @@ public:
} }
template<typename... Args> template<typename... Args>
void trace(wformat_string_t<Args...> fmt, Args &&... args) void trace(wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(level::trace, fmt, std::forward<Args>(args)...); log(level::trace, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void debug(wformat_string_t<Args...> fmt, Args &&... args) void debug(wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(level::debug, fmt, std::forward<Args>(args)...); log(level::debug, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void info(wformat_string_t<Args...> fmt, Args &&... args) void info(wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(level::info, fmt, std::forward<Args>(args)...); log(level::info, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void warn(wformat_string_t<Args...> fmt, Args &&... args) void warn(wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(level::warn, fmt, std::forward<Args>(args)...); log(level::warn, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void error(wformat_string_t<Args...> fmt, Args &&... args) void error(wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(level::err, fmt, std::forward<Args>(args)...); log(level::err, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
void critical(wformat_string_t<Args...> fmt, Args &&... args) void critical(wformat_string_t<Args...> fmt, Args &&...args)
{ {
log(level::critical, fmt, std::forward<Args>(args)...); log(level::critical, fmt, std::forward<Args>(args)...);
} }
@ -358,7 +358,7 @@ protected:
// common implementation for after templated public api has been resolved // common implementation for after templated public api has been resolved
template<typename... Args> template<typename... Args>
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 log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled(); bool traceback_enabled = tracer_.enabled();
@ -370,7 +370,7 @@ protected:
{ {
memory_buf_t buf; memory_buf_t buf;
#ifdef SPDLOG_USE_STD_FORMAT #ifdef SPDLOG_USE_STD_FORMAT
fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(std::forward<Args>(args)...)); fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...));
#else #else
fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...)); fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...));
#endif #endif
@ -383,7 +383,7 @@ protected:
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args> template<typename... Args>
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 log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled(); bool traceback_enabled = tracer_.enabled();
@ -395,8 +395,7 @@ protected:
{ {
// format to wmemory_buffer and convert to utf8 // format to wmemory_buffer and convert to utf8
wmemory_buf_t wbuf; wmemory_buf_t wbuf;
fmt_lib::vformat_to( fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, fmt_lib::make_format_args<fmt_lib::wformat_context>(args...));
std::back_inserter(wbuf), fmt, fmt_lib::make_format_args<fmt_lib::wformat_context>(std::forward<Args>(args)...));
memory_buf_t buf; memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf); details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);

@ -92,7 +92,7 @@ public:
void format(const details::log_msg &msg, memory_buf_t &dest) override; void format(const details::log_msg &msg, memory_buf_t &dest) override;
template<typename T, typename... Args> template<typename T, typename... Args>
pattern_formatter &add_flag(char flag, Args &&... args) pattern_formatter &add_flag(char flag, Args &&...args)
{ {
custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...); custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...);
return *this; return *this;

@ -21,20 +21,20 @@ SPDLOG_INLINE ansicolor_sink<ConsoleMutex>::ansicolor_sink(FILE *target_file, co
{ {
set_color_mode(mode); set_color_mode(mode);
colors_[level::trace] = to_string_(white); colors_.at(level::trace) = to_string_(white);
colors_[level::debug] = to_string_(cyan); colors_.at(level::debug) = to_string_(cyan);
colors_[level::info] = to_string_(green); colors_.at(level::info) = to_string_(green);
colors_[level::warn] = to_string_(yellow_bold); colors_.at(level::warn) = to_string_(yellow_bold);
colors_[level::err] = to_string_(red_bold); colors_.at(level::err) = to_string_(red_bold);
colors_[level::critical] = to_string_(bold_on_red); colors_.at(level::critical) = to_string_(bold_on_red);
colors_[level::off] = to_string_(reset); colors_.at(level::off) = to_string_(reset);
} }
template<typename ConsoleMutex> template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color) SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color)
{ {
std::lock_guard<mutex_t> lock(mutex_); std::lock_guard<mutex_t> lock(mutex_);
colors_[static_cast<size_t>(color_level)] = to_string_(color); colors_.at(static_cast<size_t>(color_level)) = to_string_(color);
} }
template<typename ConsoleMutex> template<typename ConsoleMutex>
@ -52,7 +52,7 @@ SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg
// before color range // before color range
print_range_(formatted, 0, msg.color_range_start); print_range_(formatted, 0, msg.color_range_start);
// in color range // in color range
print_ccode_(colors_[static_cast<size_t>(msg.level)]); print_ccode_(colors_.at(static_cast<size_t>(msg.level)));
print_range_(formatted, msg.color_range_start, msg.color_range_end); print_range_(formatted, msg.color_range_start, msg.color_range_end);
print_ccode_(reset); print_ccode_(reset);
// after color range // after color range

@ -50,12 +50,12 @@ struct daily_filename_format_calculator
static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) static filename_t calc_filename(const filename_t &file_path, const tm &now_tm)
{ {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
std::wstringstream stream; std::wstringstream stream;
#else #else
std::stringstream stream; std::stringstream stream;
#endif #endif
stream << std::put_time(&now_tm, file_path.c_str()); stream << std::put_time(&now_tm, file_path.c_str());
return stream.str(); return stream.str();
} }
}; };

@ -28,12 +28,12 @@ struct kafka_sink_config
{ {
std::string server_addr; std::string server_addr;
std::string produce_topic; 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) kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000)
: server_addr{std::move(addr)} : server_addr{std::move(addr)}
,produce_topic{std::move(topic)} , produce_topic{std::move(topic)}
,flush_timeout_ms(flush_timeout_ms) , flush_timeout_ms(flush_timeout_ms)
{} {}
}; };
@ -42,8 +42,8 @@ class kafka_sink : public base_sink<Mutex>
{ {
public: public:
kafka_sink(kafka_sink_config config) kafka_sink(kafka_sink_config config)
: config_{std::move(config)} : config_{std::move(config)}
{ {
try try
{ {
std::string errstr; std::string errstr;
@ -75,7 +75,7 @@ public:
{ {
throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what())); throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what()));
} }
} }
~kafka_sink() ~kafka_sink()
{ {
@ -85,7 +85,7 @@ public:
protected: protected:
void sink_it_(const details::log_msg &msg) override 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 void flush_() override
@ -104,7 +104,7 @@ private:
using kafka_sink_mt = kafka_sink<std::mutex>; using kafka_sink_mt = kafka_sink<std::mutex>;
using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>; using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>;
} // namespace sinks } // namespace sinks
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) inline std::shared_ptr<logger> kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config)
@ -121,13 +121,13 @@ inline std::shared_ptr<logger> kafka_logger_st(const std::string &logger_name, s
template<typename Factory = spdlog::async_factory> template<typename Factory = spdlog::async_factory>
inline std::shared_ptr<spdlog::logger> kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config) inline std::shared_ptr<spdlog::logger> kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config)
{ {
return Factory::template create<sinks::kafka_sink_mt>(logger_name, config); return Factory::template create<sinks::kafka_sink_mt>(logger_name, config);
} }
template<typename Factory = spdlog::async_factory> template<typename Factory = spdlog::async_factory>
inline std::shared_ptr<spdlog::logger> kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config) inline std::shared_ptr<spdlog::logger> kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config)
{ {
return Factory::template create<sinks::kafka_sink_st>(logger_name, config); return Factory::template create<sinks::kafka_sink_st>(logger_name, config);
} }
} // namespace spdlog } // namespace spdlog

@ -3,7 +3,6 @@
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
# include <spdlog/details/null_mutex.h> # include <spdlog/details/null_mutex.h>
@ -16,11 +15,11 @@
# include <string> # include <string>
// Avoid including windows.h (https://stackoverflow.com/a/30741042) // 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); extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString);
#else # else
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString);
#endif # endif
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
namespace spdlog { namespace spdlog {
@ -46,13 +45,13 @@ protected:
memory_buf_t formatted; memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted); base_sink<Mutex>::formatter_->format(msg, formatted);
formatted.push_back('\0'); // add a null terminator for OutputDebugString 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; wmemory_buf_t wformatted;
details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted);
OutputDebugStringW(wformatted.data()); OutputDebugStringW(wformatted.data());
#else # else
OutputDebugStringA(formatted.data()); OutputDebugStringA(formatted.data());
#endif # endif
} }
void flush_() override {} void flush_() override {}

@ -7,11 +7,16 @@
// Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... // Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser...
// etc) Building and using requires Qt library. // 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/common.h"
#include "spdlog/details/log_msg.h" #include "spdlog/details/log_msg.h"
#include "spdlog/details/synchronous_factory.h" #include "spdlog/details/synchronous_factory.h"
#include "spdlog/sinks/base_sink.h" #include "spdlog/sinks/base_sink.h"
#include <array>
#include <QTextEdit> #include <QTextEdit>
#include <QPlainTextEdit> #include <QPlainTextEdit>
@ -53,15 +58,185 @@ private:
std::string meta_method_; 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<typename Mutex>
class qt_color_sink : public base_sink<Mutex>
{
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<Mutex> lock(base_sink<Mutex>::mutex_);
default_color_ = format;
}
void set_level_color(level::level_enum color_level, QTextCharFormat format)
{
// std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
colors_.at(static_cast<size_t>(color_level)) = format;
}
QTextCharFormat &get_level_color(level::level_enum color_level)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
return colors_.at(static_cast<size_t>(color_level));
}
QTextCharFormat &get_default_color()
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::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<Mutex>;
memory_buf_t formatted;
base_sink<Mutex>::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<int>(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<QTextCharFormat, level::n_levels> colors_;
};
#include "spdlog/details/null_mutex.h" #include "spdlog/details/null_mutex.h"
#include <mutex> #include <mutex>
using qt_sink_mt = qt_sink<std::mutex>; using qt_sink_mt = qt_sink<std::mutex>;
using qt_sink_st = qt_sink<spdlog::details::null_mutex>; using qt_sink_st = qt_sink<details::null_mutex>;
using qt_color_sink_mt = qt_color_sink<std::mutex>;
using qt_color_sink_st = qt_color_sink<details::null_mutex>;
} // namespace sinks } // namespace sinks
// //
// Factory functions // Factory functions
// //
// log to QTextEdit
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") inline std::shared_ptr<logger> 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<logger> qt_logger_st(const std::string &logger_name, QTex
return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method); return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
} }
// log to QPlainTextEdit
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_mt( inline std::shared_ptr<logger> qt_logger_mt(
const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText")
@ -87,7 +263,7 @@ inline std::shared_ptr<logger> qt_logger_st(
{ {
return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method); return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
} }
// log to QObject
template<typename Factory = spdlog::synchronous_factory> template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) inline std::shared_ptr<logger> qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method)
{ {
@ -99,4 +275,18 @@ inline std::shared_ptr<logger> qt_logger_st(const std::string &logger_name, QObj
{ {
return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method); return Factory::template create<sinks::qt_sink_st>(logger_name, qt_object, meta_method);
} }
// log to QTextEdit with colorize output
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines)
{
return Factory::template create<sinks::qt_color_sink_mt >(logger_name, qt_text_edit, max_lines);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines)
{
return Factory::template create<sinks::qt_color_sink_st >(logger_name, qt_text_edit, max_lines);
}
} // namespace spdlog } // namespace spdlog

@ -72,7 +72,7 @@ SPDLOG_INLINE void stdout_sink_base<ConsoleMutex>::log(const details::log_msg &m
memory_buf_t formatted; memory_buf_t formatted;
formatter_->format(msg, formatted); formatter_->format(msg, formatted);
::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_);
#endif // WIN32 #endif // WIN32
::fflush(file_); // flush every line to terminal ::fflush(file_); // flush every line to terminal
} }

@ -241,12 +241,12 @@ protected:
details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf);
LPCWSTR lp_wstr = buf.data(); LPCWSTR lp_wstr = buf.data();
succeeded = static_cast<bool>(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, succeeded = static_cast<bool>(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg),
current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); event_id_, current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr));
#else #else
LPCSTR lp_str = formatted.data(); LPCSTR lp_str = formatted.data();
succeeded = static_cast<bool>(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, succeeded = static_cast<bool>(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg),
current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); event_id_, current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr));
#endif #endif
if (!succeeded) if (!succeeded)

@ -32,7 +32,7 @@ using default_factory = synchronous_factory;
// Example: // Example:
// spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59); // spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59);
template<typename Sink, typename... SinkArgs> template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... sink_args) inline std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&...sink_args)
{ {
return default_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); return default_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
} }
@ -142,49 +142,49 @@ SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logge
SPDLOG_API void apply_logger_env_levels(std::shared_ptr<logger> logger); SPDLOG_API void apply_logger_env_levels(std::shared_ptr<logger> logger);
template<typename... Args> template<typename... Args>
inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...); default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) inline void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void trace(format_string_t<Args...> fmt, Args &&... args) inline void trace(format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->trace(fmt, std::forward<Args>(args)...); default_logger_raw()->trace(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void debug(format_string_t<Args...> fmt, Args &&... args) inline void debug(format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->debug(fmt, std::forward<Args>(args)...); default_logger_raw()->debug(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void info(format_string_t<Args...> fmt, Args &&... args) inline void info(format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->info(fmt, std::forward<Args>(args)...); default_logger_raw()->info(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void warn(format_string_t<Args...> fmt, Args &&... args) inline void warn(format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->warn(fmt, std::forward<Args>(args)...); default_logger_raw()->warn(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void error(format_string_t<Args...> fmt, Args &&... args) inline void error(format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->error(fmt, std::forward<Args>(args)...); default_logger_raw()->error(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void critical(format_string_t<Args...> fmt, Args &&... args) inline void critical(format_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->critical(fmt, std::forward<Args>(args)...); default_logger_raw()->critical(fmt, std::forward<Args>(args)...);
} }
@ -203,49 +203,49 @@ inline void log(level::level_enum lvl, const T &msg)
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args> template<typename... Args>
inline void log(source_loc source, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args) inline void log(source_loc source, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...); default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args) inline void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void trace(wformat_string_t<Args...> fmt, Args &&... args) inline void trace(wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->trace(fmt, std::forward<Args>(args)...); default_logger_raw()->trace(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void debug(wformat_string_t<Args...> fmt, Args &&... args) inline void debug(wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->debug(fmt, std::forward<Args>(args)...); default_logger_raw()->debug(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void info(wformat_string_t<Args...> fmt, Args &&... args) inline void info(wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->info(fmt, std::forward<Args>(args)...); default_logger_raw()->info(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void warn(wformat_string_t<Args...> fmt, Args &&... args) inline void warn(wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->warn(fmt, std::forward<Args>(args)...); default_logger_raw()->warn(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void error(wformat_string_t<Args...> fmt, Args &&... args) inline void error(wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->error(fmt, std::forward<Args>(args)...); default_logger_raw()->error(fmt, std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
inline void critical(wformat_string_t<Args...> fmt, Args &&... args) inline void critical(wformat_string_t<Args...> fmt, Args &&...args)
{ {
default_logger_raw()->critical(fmt, std::forward<Args>(args)...); default_logger_raw()->critical(fmt, std::forward<Args>(args)...);
} }

@ -14,16 +14,12 @@ if(PkgConfig_FOUND)
endif() endif()
find_package(Catch2 3 QUIET) find_package(Catch2 3 QUIET)
if (Catch2_FOUND) if(Catch2_FOUND)
message(STATUS "Packaged version of Catch will be used.") message(STATUS "Packaged version of Catch will be used.")
else() else()
message(STATUS "Bundled version of Catch will be downloaded and used.") message(STATUS "Bundled version of Catch will be downloaded and used.")
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.3.2)
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.3.2
)
FetchContent_MakeAvailable(Catch2) FetchContent_MakeAvailable(Catch2)
endif() endif()

@ -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 "includes.h"
#include <iostream> #include <iostream>
@ -11,114 +11,114 @@
class failing_sink : public spdlog::sinks::base_sink<std::mutex> class failing_sink : public spdlog::sinks::base_sink<std::mutex>
{ {
protected: protected:
void sink_it_(const spdlog::details::log_msg &) final void sink_it_(const spdlog::details::log_msg &) final
{ {
throw std::runtime_error("some error happened during log"); throw std::runtime_error("some error happened during log");
} }
void flush_() final void flush_() final
{ {
throw std::runtime_error("some error happened during flush"); 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 #if !defined(SPDLOG_USE_STD_FORMAT) // std formt doesn't fully support tuntime strings
TEST_CASE("default_error_handler", "[errors]") TEST_CASE("default_error_handler", "[errors]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
logger->set_pattern("%v"); logger->set_pattern("%v");
logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1); logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1);
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
logger->flush(); logger->flush();
using spdlog::details::os::default_eol; using spdlog::details::os::default_eol;
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol)); REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol));
REQUIRE(count_lines(SIMPLE_LOG) == 1); REQUIRE(count_lines(SIMPLE_LOG) == 1);
} }
TEST_CASE("custom_error_handler", "[errors]") TEST_CASE("custom_error_handler", "[errors]")
{ {
prepare_logdir(); prepare_logdir();
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->flush_on(spdlog::level::info); logger->flush_on(spdlog::level::info);
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
logger->info("Good message #1"); logger->info("Good message #1");
REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex);
logger->info("Good message #2"); logger->info("Good message #2");
require_message_count(SIMPLE_LOG, 2); require_message_count(SIMPLE_LOG, 2);
} }
#endif #endif
TEST_CASE("default_error_handler2", "[errors]") TEST_CASE("default_error_handler2", "[errors]")
{ {
spdlog::drop_all(); spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
} }
TEST_CASE("flush_error_handler", "[errors]") TEST_CASE("flush_error_handler", "[errors]")
{ {
spdlog::drop_all(); spdlog::drop_all();
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
REQUIRE_THROWS_AS(logger->flush(), custom_ex); REQUIRE_THROWS_AS(logger->flush(), custom_ex);
} }
#if !defined(SPDLOG_USE_STD_FORMAT) #if !defined(SPDLOG_USE_STD_FORMAT)
TEST_CASE("async_error_handler", "[errors]") TEST_CASE("async_error_handler", "[errors]")
{ {
prepare_logdir(); prepare_logdir();
std::string err_msg("log failed with some msg"); std::string err_msg("log failed with some msg");
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG); spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG);
{ {
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true); auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string &) { logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err.txt"); std::ofstream ofs("test_logs/custom_err.txt");
if (!ofs) if (!ofs)
{ {
throw std::runtime_error("Failed open test_logs/custom_err.txt"); throw std::runtime_error("Failed open test_logs/custom_err.txt");
} }
ofs << err_msg; ofs << err_msg;
}); });
logger->info("Good message #1"); logger->info("Good message #1");
logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"); logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx");
logger->info("Good message #2"); logger->info("Good message #2");
spdlog::drop("logger"); // force logger to drain the queue and shutdown spdlog::drop("logger"); // force logger to drain the queue and shutdown
} }
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
require_message_count(SIMPLE_ASYNC_LOG, 2); require_message_count(SIMPLE_ASYNC_LOG, 2);
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
} }
#endif #endif
// Make sure async error handler is executed // Make sure async error handler is executed
TEST_CASE("async_error_handler2", "[errors]") TEST_CASE("async_error_handler2", "[errors]")
{ {
prepare_logdir(); prepare_logdir();
std::string err_msg("This is async handler error message"); std::string err_msg("This is async handler error message");
{ {
spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs")); spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs"));
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_async<failing_sink>("failed_logger"); auto logger = spdlog::create_async<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &) { logger->set_error_handler([=](const std::string &) {
std::ofstream ofs("test_logs/custom_err2.txt"); std::ofstream ofs("test_logs/custom_err2.txt");
if (!ofs) if (!ofs)
throw std::runtime_error("Failed open test_logs/custom_err2.txt"); throw std::runtime_error("Failed open test_logs/custom_err2.txt");
ofs << err_msg; ofs << err_msg;
}); });
logger->info("Hello failure"); logger->info("Hello failure");
spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown
} }
spdlog::init_thread_pool(128, 1); spdlog::init_thread_pool(128, 1);
REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg); REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg);
} }

@ -6,7 +6,7 @@ using spdlog::details::to_string_view;
// log to str and return it // log to str and return it
template<typename... Args> template<typename... Args>
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; std::ostringstream oss;
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss); auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);

Loading…
Cancel
Save