From 0fd3e80794ebb117cdf69781f320ee7a95495562 Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 4 Jan 2025 15:59:05 +0200 Subject: [PATCH] error handler wip --- CMakeLists.txt | 292 +++++++++++++------------ include/spdlog/details/error_handler.h | 33 +++ include/spdlog/logger.h | 23 +- include/spdlog/sinks/async_sink.h | 3 +- src/details/error_handler.cpp | 55 +++++ src/logger.cpp | 31 +-- src/sinks/async_sink.cpp | 21 +- 7 files changed, 258 insertions(+), 200 deletions(-) create mode 100644 include/spdlog/details/error_handler.h create mode 100644 src/details/error_handler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fd70be6..40541047 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,38 +19,38 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) # --------------------------------------------------------------------------------------- # Set default build to release # --------------------------------------------------------------------------------------- -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) -endif() +endif () # --------------------------------------------------------------------------------------- # Compiler config # --------------------------------------------------------------------------------------- # c++ standard >=17 is required -if(NOT DEFINED CMAKE_CXX_STANDARD) +if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 17) -elseif(CMAKE_CXX_STANDARD LESS 17) +elseif (CMAKE_CXX_STANDARD LESS 17) message(FATAL_ERROR "Minimum supported CMAKE_CXX_STANDARD is 17, but it is set to ${CMAKE_CXX_STANDARD}") -endif() +endif () set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS" OR CMAKE_SYSTEM_NAME MATCHES "MINGW") +if (CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS" OR CMAKE_SYSTEM_NAME MATCHES "MINGW") set(CMAKE_CXX_EXTENSIONS ON) -endif() +endif () # --------------------------------------------------------------------------------------- # Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog # --------------------------------------------------------------------------------------- # Check if spdlog is being used directly or via add_subdirectory, but allow overriding -if(NOT DEFINED SPDLOG_MASTER_PROJECT) - if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) +if (NOT DEFINED SPDLOG_MASTER_PROJECT) + if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(SPDLOG_MASTER_PROJECT ON) - else() + else () set(SPDLOG_MASTER_PROJECT OFF) - endif() -endif() + endif () +endif () option(SPDLOG_BUILD_ALL "Build all artifacts" OFF) @@ -77,11 +77,11 @@ option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of of fetching from gitub." OFF) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") option(SPDLOG_CLOCK_COARSE "Use CLOCK_REALTIME_COARSE instead of the regular clock," OFF) -else() +else () set(SPDLOG_CLOCK_COARSE OFF CACHE BOOL "non supported option" FORCE) -endif() +endif () option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF) option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF) @@ -91,18 +91,18 @@ option(SPDLOG_NO_TLS "Disable thread local storage" OFF) # clang-tidy option(SPDLOG_TIDY "run clang-tidy" OFF) -if(SPDLOG_TIDY) +if (SPDLOG_TIDY) set(CMAKE_CXX_CLANG_TIDY "clang-tidy") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) message(STATUS "Enabled clang-tidy") -endif() +endif () -if(SPDLOG_BUILD_SHARED) +if (SPDLOG_BUILD_SHARED) set(BUILD_SHARED_LIBS ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -endif() +endif () -if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # place dlls and libs and executables in the same directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$) @@ -113,7 +113,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_compile_options(/Zc:__cplusplus) # enable parallel build for the solution add_compile_options(/MP) -endif() +endif () message(STATUS "spdlog version: ${SPDLOG_VERSION}") message(STATUS "spdlog build type: " ${CMAKE_BUILD_TYPE}) @@ -123,12 +123,12 @@ message(STATUS "spdlog fmt external: " ${SPDLOG_FMT_EXTERNAL}) # --------------------------------------------------------------------------------------- # Find {fmt} library # --------------------------------------------------------------------------------------- -if(SPDLOG_FMT_EXTERNAL) +if (SPDLOG_FMT_EXTERNAL) find_package(fmt REQUIRED) message(STATUS "Using external fmt lib version: ${fmt_VERSION}") -else() +else () include(cmake/fmtlib.cmake) -endif() +endif () # --------------------------------------------------------------------------------------- # Threads library is required @@ -139,196 +139,198 @@ find_package(Threads REQUIRED) # Library sources # --------------------------------------------------------------------------------------- set(SPDLOG_HEADERS - "include/spdlog/common.h" - "include/spdlog/formatter.h" - "include/spdlog/fwd.h" - "include/spdlog/logger.h" - "include/spdlog/pattern_formatter.h" - "include/spdlog/source_loc.h" - "include/spdlog/spdlog.h" - "include/spdlog/stopwatch.h" - "include/spdlog/version.h" - "include/spdlog/details/circular_q.h" - "include/spdlog/details/file_helper.h" - "include/spdlog/details/fmt_helper.h" - "include/spdlog/details/log_msg.h" - "include/spdlog/details/async_log_msg.h" - "include/spdlog/details/mpmc_blocking_q.h" - "include/spdlog/details/null_mutex.h" - "include/spdlog/details/os.h" - "include/spdlog/bin_to_hex.h" - "include/spdlog/sinks/android_sink.h" - "include/spdlog/sinks/base_sink.h" - "include/spdlog/sinks/basic_file_sink.h" - "include/spdlog/sinks/callback_sink.h" - "include/spdlog/sinks/daily_file_sink.h" - "include/spdlog/sinks/dist_sink.h" - "include/spdlog/sinks/dup_filter_sink.h" - "include/spdlog/sinks/hourly_file_sink.h" - "include/spdlog/sinks/kafka_sink.h" - "include/spdlog/sinks/mongo_sink.h" - "include/spdlog/sinks/msvc_sink.h" - "include/spdlog/sinks/null_sink.h" - "include/spdlog/sinks/ostream_sink.h" - "include/spdlog/sinks/qt_sinks.h" - "include/spdlog/sinks/ringbuffer_sink.h" - "include/spdlog/sinks/rotating_file_sink.h" - "include/spdlog/sinks/sink.h" - "include/spdlog/sinks/stdout_color_sinks.h" - "include/spdlog/sinks/stdout_sinks.h" - "include/spdlog/sinks/syslog_sink.h" - "include/spdlog/sinks/systemd_sink.h" - "include/spdlog/sinks/tcp_sink.h" - "include/spdlog/sinks/udp_sink.h" - "include/spdlog/sinks/async_sink.h") + "include/spdlog/common.h" + "include/spdlog/formatter.h" + "include/spdlog/fwd.h" + "include/spdlog/logger.h" + "include/spdlog/pattern_formatter.h" + "include/spdlog/source_loc.h" + "include/spdlog/spdlog.h" + "include/spdlog/stopwatch.h" + "include/spdlog/version.h" + "include/spdlog/details/circular_q.h" + "include/spdlog/details/file_helper.h" + "include/spdlog/details/fmt_helper.h" + "include/spdlog/details/log_msg.h" + "include/spdlog/details/async_log_msg.h" + "include/spdlog/details/mpmc_blocking_q.h" + "include/spdlog/details/null_mutex.h" + "include/spdlog/details/os.h" + "include/spdlog/details/error_handler.h" + "include/spdlog/bin_to_hex.h" + "include/spdlog/sinks/android_sink.h" + "include/spdlog/sinks/base_sink.h" + "include/spdlog/sinks/basic_file_sink.h" + "include/spdlog/sinks/callback_sink.h" + "include/spdlog/sinks/daily_file_sink.h" + "include/spdlog/sinks/dist_sink.h" + "include/spdlog/sinks/dup_filter_sink.h" + "include/spdlog/sinks/hourly_file_sink.h" + "include/spdlog/sinks/kafka_sink.h" + "include/spdlog/sinks/mongo_sink.h" + "include/spdlog/sinks/msvc_sink.h" + "include/spdlog/sinks/null_sink.h" + "include/spdlog/sinks/ostream_sink.h" + "include/spdlog/sinks/qt_sinks.h" + "include/spdlog/sinks/ringbuffer_sink.h" + "include/spdlog/sinks/rotating_file_sink.h" + "include/spdlog/sinks/sink.h" + "include/spdlog/sinks/stdout_color_sinks.h" + "include/spdlog/sinks/stdout_sinks.h" + "include/spdlog/sinks/syslog_sink.h" + "include/spdlog/sinks/systemd_sink.h" + "include/spdlog/sinks/tcp_sink.h" + "include/spdlog/sinks/udp_sink.h" + "include/spdlog/sinks/async_sink.h") set(SPDLOG_SRCS - "src/common.cpp" - "src/logger.cpp" - "src/pattern_formatter.cpp" - "src/spdlog.cpp" - "src/details/file_helper.cpp" - "src/details/os_filesystem.cpp" - "src/details/log_msg.cpp" - "src/details/async_log_msg.cpp" + "src/common.cpp" + "src/logger.cpp" + "src/pattern_formatter.cpp" + "src/spdlog.cpp" + "src/details/file_helper.cpp" + "src/details/os_filesystem.cpp" + "src/details/log_msg.cpp" + "src/details/async_log_msg.cpp" + "src/details/error_handler.cpp" "src/sinks/base_sink.cpp" - "src/sinks/basic_file_sink.cpp" - "src/sinks/rotating_file_sink.cpp" - "src/sinks/stdout_sinks.cpp" - "src/sinks/async_sink.cpp") + "src/sinks/basic_file_sink.cpp" + "src/sinks/rotating_file_sink.cpp" + "src/sinks/stdout_sinks.cpp" + "src/sinks/async_sink.cpp") -if(WIN32) +if (WIN32) list(APPEND SPDLOG_SRCS - "src/details/os_windows.cpp" - "src/sinks/wincolor_sink.cpp") + "src/details/os_windows.cpp" + "src/sinks/wincolor_sink.cpp") list(APPEND SPDLOG_HEADERS - "include/spdlog/sinks/wincolor_sink.h" - "include/spdlog/details/tcp_client_windows.h" - "include/spdlog/details/udp_client_windows.h" - "include/spdlog/details/windows_include.h" - "include/spdlog/sinks/win_eventlog_sink.h") -else() + "include/spdlog/sinks/wincolor_sink.h" + "include/spdlog/details/tcp_client_windows.h" + "include/spdlog/details/udp_client_windows.h" + "include/spdlog/details/windows_include.h" + "include/spdlog/sinks/win_eventlog_sink.h") +else () list(APPEND SPDLOG_SRCS - "src/details/os_unix.cpp" - "src/sinks/ansicolor_sink.cpp") + "src/details/os_unix.cpp" + "src/sinks/ansicolor_sink.cpp") list(APPEND SPDLOG_HEADERS - "include/spdlog/details/tcp_client_unix.h" - "include/spdlog/details/udp_client_unix.h" - "include/spdlog/sinks/ansicolor_sink.h") -endif() + "include/spdlog/details/tcp_client_unix.h" + "include/spdlog/details/udp_client_unix.h" + "include/spdlog/sinks/ansicolor_sink.h") +endif () # --------------------------------------------------------------------------------------- # Check if fwrite_unlocked/_fwrite_nolock is available # --------------------------------------------------------------------------------------- include(CheckSymbolExists) -if(WIN32) +if (WIN32) check_symbol_exists(_fwrite_nolock "stdio.h" HAVE_FWRITE_UNLOCKED) -else() +else () check_symbol_exists(fwrite_unlocked "stdio.h" HAVE_FWRITE_UNLOCKED) -endif() -if(HAVE_FWRITE_UNLOCKED) +endif () +if (HAVE_FWRITE_UNLOCKED) set(SPDLOG_FWRITE_UNLOCKED 1) -endif() +endif () # --------------------------------------------------------------------------------------- # spdlog library # --------------------------------------------------------------------------------------- -if(BUILD_SHARED_LIBS) - if(WIN32) +if (BUILD_SHARED_LIBS) + if (WIN32) set(VERSION_RC ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) - endif() + endif () add_library(spdlog SHARED ${VERSION_RC}) target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB) - if(MSVC) + if (MSVC) # disable dlls related warnings on msvc target_compile_options(spdlog PUBLIC $<$,$>>:/wd4251 - /wd4275>) - endif() -else() + /wd4275>) + endif () +else () add_library(spdlog STATIC) -endif() +endif () add_library(spdlog::spdlog ALIAS spdlog) target_sources(spdlog PRIVATE ${SPDLOG_SRCS}) target_sources( - spdlog - PUBLIC FILE_SET pub_headers - TYPE HEADERS - BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include - FILES ${SPDLOG_HEADERS}) + spdlog + PUBLIC FILE_SET pub_headers + TYPE HEADERS + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include + FILES ${SPDLOG_HEADERS}) set(SPDLOG_INCLUDES_LEVEL "") -if(SPDLOG_SYSTEM_INCLUDES) +if (SPDLOG_SYSTEM_INCLUDES) set(SPDLOG_INCLUDES_LEVEL "SYSTEM") -endif() +endif () target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$" - "$") + "$") target_link_libraries(spdlog PUBLIC Threads::Threads) target_link_libraries(spdlog PUBLIC fmt::fmt) spdlog_enable_warnings(spdlog) set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION - ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}) + ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}) set(SPDLOG_NAME spdlog-${SPDLOG_VERSION_MAJOR}) -set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX "-${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}d") +set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX "-${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}d") # --------------------------------------------------------------------------------------- # set source groups for visual studio # --------------------------------------------------------------------------------------- -if(CMAKE_GENERATOR MATCHES "Visual Studio") +if (CMAKE_GENERATOR MATCHES "Visual Studio") source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/include PREFIX include FILES ${SPDLOG_HEADERS}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/src PREFIX sources FILES ${SPDLOG_SRCS}) source_group(sources FILES ${VERSION_RC}) -endif() +endif () # --------------------------------------------------------------------------------------- # Add required libraries for Android CMake build # --------------------------------------------------------------------------------------- -if(ANDROID) +if (ANDROID) target_link_libraries(spdlog PUBLIC log) -endif() +endif () # --------------------------------------------------------------------------------------- # spdlog private defines according to the options # --------------------------------------------------------------------------------------- -foreach(SPDLOG_OPTION - SPDLOG_CLOCK_COARSE - SPDLOG_PREVENT_CHILD_FD - SPDLOG_NO_THREAD_ID - SPDLOG_DISABLE_GLOBAL_LOGGER - SPDLOG_NO_TLS - SPDLOG_FWRITE_UNLOCKED) - if(${SPDLOG_OPTION}) +foreach (SPDLOG_OPTION + SPDLOG_CLOCK_COARSE + SPDLOG_PREVENT_CHILD_FD + SPDLOG_NO_THREAD_ID + SPDLOG_DISABLE_GLOBAL_LOGGER + SPDLOG_NO_TLS + SPDLOG_FWRITE_UNLOCKED) + if (${SPDLOG_OPTION}) target_compile_definitions(spdlog PRIVATE ${SPDLOG_OPTION}) - endif() -endforeach() + endif () +endforeach () # --------------------------------------------------------------------------------------- # Build binaries # --------------------------------------------------------------------------------------- -if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_ALL) +if (SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_ALL) message(STATUS "Generating example(s)") add_subdirectory(example) spdlog_enable_warnings(example) -endif() +endif () -if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_ALL) +if (SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_ALL) message(STATUS "Generating tests") enable_testing() add_subdirectory(tests) -endif() +endif () -if(SPDLOG_BUILD_BENCH OR SPDLOG_BUILD_ALL) +if (SPDLOG_BUILD_BENCH OR SPDLOG_BUILD_ALL) message(STATUS "Generating benchmarks") add_subdirectory(bench) -endif() +endif () # --------------------------------------------------------------------------------------- # Install # --------------------------------------------------------------------------------------- -if(SPDLOG_INSTALL) +if (SPDLOG_INSTALL) message(STATUS "Generating install") set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in") set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake") @@ -341,13 +343,13 @@ if(SPDLOG_INSTALL) # --------------------------------------------------------------------------------------- set(installed_include_dir "${CMAKE_INSTALL_INCLUDEDIR}/${SPDLOG_NAME}") install( - TARGETS spdlog - EXPORT spdlogTargets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/${SPDLOG_NAME}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/${SPDLOG_NAME}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/${SPDLOG_NAME}" - FILE_SET pub_headers - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${SPDLOG_NAME}") + TARGETS spdlog + EXPORT spdlogTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/${SPDLOG_NAME}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/${SPDLOG_NAME}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/${SPDLOG_NAME}" + FILE_SET pub_headers + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${SPDLOG_NAME}") message(STATUS "Installing spdlog in ${CMAKE_INSTALL_LIBDIR}/${SPDLOG_NAME}") # --------------------------------------------------------------------------------------- @@ -365,4 +367,4 @@ if(SPDLOG_INSTALL) # Support creation of installable packages # --------------------------------------------------------------------------------------- include(cmake/spdlogCPack.cmake) -endif() +endif () diff --git a/include/spdlog/details/error_handler.h b/include/spdlog/details/error_handler.h new file mode 100644 index 00000000..15db0f9e --- /dev/null +++ b/include/spdlog/details/error_handler.h @@ -0,0 +1,33 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include "spdlog/common.h" + +// by default, prints the error to stderr. thread safe. +namespace spdlog { +namespace details { +class error_handler { +public: + explicit error_handler(std::string name); + error_handler(const error_handler &); + error_handler(error_handler &&) noexcept; + // for simplicity allow only construction of this class. + // otherwise we need to deal with mutexes and potential deadlocks. + error_handler &operator=(const error_handler &) = delete; + error_handler &operator=(error_handler &&) = delete; + void handle(const source_loc& loc, const std::string &err_msg) const; + void set_name(const std::string& name); + void set_custom_handler(err_handler handler); + +private: + mutable std::mutex mutex_; + std::string name_; + err_handler custom_handler_ = nullptr; +}; + + +}} // namespace spdlog::details diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index d430229f..46ea415d 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -20,19 +20,15 @@ #include "common.h" #include "details/log_msg.h" +#include "details/error_handler.h" #include "sinks/sink.h" #define SPDLOG_LOGGER_CATCH(location) \ catch (const std::exception &ex) { \ - if (!location.empty()) { \ - err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \ - } else { \ - err_handler_(ex.what()); \ - } \ + err_handler_.handle(location, ex.what()); \ } \ catch (...) { \ - err_handler_("Rethrowing unknown exception in logger"); \ - throw; \ + err_handler_.handle(location, "Unknown exception"); \ } namespace spdlog { @@ -41,13 +37,15 @@ class SPDLOG_API logger { public: // Empty logger explicit logger(std::string name) - : name_(std::move(name)) {} + : name_(name), + err_handler_(std::move(name)) {} // Logger with range on sinks template logger(std::string name, It begin, It end) - : name_(std::move(name)), - sinks_(begin, end) {} + : name_(name), + sinks_(begin, end), + err_handler_(std::move(name)) {} // Logger with single sink logger(std::string name, sink_ptr single_sink) @@ -175,7 +173,7 @@ private: std::vector sinks_; atomic_level_t level_{level::info}; atomic_level_t flush_level_{level::off}; - err_handler custom_err_handler_{nullptr}; + details::error_handler err_handler_; // common implementation for after templated public api has been resolved to format string and // args @@ -208,9 +206,6 @@ private: } void flush_(); [[nodiscard]] bool should_flush_(const details::log_msg &msg) const; - - // default handler prints the error to stderr - void err_handler_(const std::string &msg); }; } // namespace spdlog diff --git a/include/spdlog/sinks/async_sink.h b/include/spdlog/sinks/async_sink.h index 3096c6e4..5a839d1d 100644 --- a/include/spdlog/sinks/async_sink.h +++ b/include/spdlog/sinks/async_sink.h @@ -8,6 +8,7 @@ #include #include "../details/async_log_msg.h" +#include "../details/error_handler.h" #include "sink.h" // async_sink is a sink that sends log messages to a dist_sink in a separate thread using a queue. @@ -73,11 +74,11 @@ private: void backend_loop_(); void backend_log_(const details::log_msg &msg) ; void backend_flush_(); - void err_handler_(const std::string &msg); config config_; std::unique_ptr q_; std::thread worker_thread_; + details::error_handler err_handler_; }; } // namespace sinks diff --git a/src/details/error_handler.cpp b/src/details/error_handler.cpp new file mode 100644 index 00000000..68d1fa68 --- /dev/null +++ b/src/details/error_handler.cpp @@ -0,0 +1,55 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#include "spdlog/details/error_handler.h" +#include "spdlog/details/os.h" +#include "iostream" + +namespace spdlog { +namespace details { + +error_handler::error_handler(std::string name) + : name_(std::move(name)) {} + +error_handler::error_handler(const error_handler &other) { + std::lock_guard lk{other.mutex_}; + name_ = other.name_; + custom_handler_ = other.custom_handler_; +} + +error_handler::error_handler(error_handler &&other) noexcept { + std::lock_guard lk{other.mutex_}; + name_ = std::move(other.name_); + custom_handler_ = std::move(other.custom_handler_); +} + +void error_handler::handle(const source_loc &loc, const std::string &err_msg) const { + std::lock_guard lk{mutex_}; + if (custom_handler_) { + custom_handler_(err_msg); + return; + } + const auto tm_time = os::localtime(); + char date_buf[128]; + std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); + std::string msg; + if (loc.empty()) { + msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}] [{}] {}\n", date_buf, name_, err_msg); + } + else { + msg = fmt_lib::format("[*** LOGGING ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, name_, err_msg); + } + std::fputs(msg.c_str(), stderr); +} +void error_handler::set_name(const std::string &name) { + std::lock_guard lk{mutex_}; + name_ = name; +} + +void error_handler::set_custom_handler(err_handler handler) { + std::lock_guard lk{mutex_}; + custom_handler_ = std::move(handler); +} + +} // namespace details +} // namespace spdlog diff --git a/src/logger.cpp b/src/logger.cpp index 600efdc1..101af0cd 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -2,9 +2,7 @@ // Distributed under the MIT License (http://opensource.org/licenses/MIT) #include "spdlog/logger.h" - #include -#include #include "spdlog/pattern_formatter.h" #include "spdlog/sinks/sink.h" @@ -17,14 +15,14 @@ logger::logger(const logger &other) noexcept sinks_(other.sinks_), level_(other.level_.load(std::memory_order_relaxed)), flush_level_(other.flush_level_.load(std::memory_order_relaxed)), - custom_err_handler_(other.custom_err_handler_) {} + err_handler_(other.err_handler_) {} logger::logger(logger &&other) noexcept : name_(std::move(other.name_)), sinks_(std::move(other.sinks_)), level_(other.level_.load(std::memory_order_relaxed)), flush_level_(other.flush_level_.load(std::memory_order_relaxed)), - custom_err_handler_(std::move(other.custom_err_handler_)) {} + err_handler_(std::move(other.err_handler_)) {} void logger::set_level(level level) { level_.store(level); } @@ -62,13 +60,16 @@ const std::vector &logger::sinks() const { return sinks_; } std::vector &logger::sinks() { return sinks_; } -// error handler -void logger::set_error_handler(err_handler handler) { custom_err_handler_ = std::move(handler); } +// custom error handler +void logger::set_error_handler(err_handler handler) { + err_handler_.set_custom_handler(std::move(handler)); +} // create new logger with same sinks and configuration. std::shared_ptr logger::clone(std::string logger_name) { auto cloned = std::make_shared(*this); cloned->name_ = std::move(logger_name); + cloned->err_handler_.set_name(cloned->name_); return cloned; } @@ -78,7 +79,7 @@ void logger::flush_() { try { sink->flush(); } - SPDLOG_LOGGER_CATCH(source_loc()) + SPDLOG_LOGGER_CATCH(source_loc{}) } } @@ -87,20 +88,4 @@ bool logger::should_flush_(const details::log_msg &msg) const { return (msg.log_level >= flush_level) && (msg.log_level != level::off); } -void logger::err_handler_(const std::string &msg) { - if (custom_err_handler_) { - custom_err_handler_(msg); - } else { - using std::chrono::system_clock; - auto now = system_clock::now(); - auto tm_time = details::os::localtime(system_clock::to_time_t(now)); - char date_buf[64]; - std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); -#if defined(USING_R) && defined(R_R_H) // if in R environment - REprintf("[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), msg.c_str()); -#else - std::fprintf(stderr, "[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), msg.c_str()); -#endif - } -} } // namespace spdlog diff --git a/src/sinks/async_sink.cpp b/src/sinks/async_sink.cpp index b9154c74..6c1f2f80 100644 --- a/src/sinks/async_sink.cpp +++ b/src/sinks/async_sink.cpp @@ -15,7 +15,7 @@ namespace spdlog { namespace sinks { async_sink::async_sink(config async_config) - : config_(std::move(async_config)) { + : config_(std::move(async_config)), err_handler_("async_sink") { if (config_.queue_size == 0 || config_.queue_size > max_queue_size) { throw spdlog_ex("async_sink: invalid queue size"); } @@ -107,7 +107,7 @@ void async_sink::backend_log_(const details::log_msg &msg) { try { sink->log(msg); } catch (const std::exception &ex) { - err_handler_(std::string("async log failed: ") + ex.what()); + err_handler_.handle(msg.source, std::string("async log failed: ") + ex.what()); } } } @@ -118,24 +118,11 @@ void async_sink::backend_flush_() { try { sink->flush(); } catch (const std::exception &ex) { - err_handler_(std::string("async flush failed: ") + ex.what()); + err_handler_.handle(source_loc{}, std::string("async flush failed: ") + ex.what()); } catch (...) { - err_handler_("Async flush failed with unknown exception"); + err_handler_.handle(source_loc{}, "Async flush failed with unknown exception"); } } } -void async_sink::err_handler_(const std::string &message) { - using std::chrono::system_clock; - const auto now = system_clock::now(); - const auto tm_time = details::os::localtime(system_clock::to_time_t(now)); - char date_buf[64]; - std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); -#if defined(USING_R) && defined(R_R_H) // if in R environment - REprintf("[*** LOG ERROR ***] [%s] [%s] %s\n", date_buf, name().c_str(), message.c_str()); -#else - std::fprintf(stderr, "[*** LOG ERROR ***] [%s] %s\n", date_buf, message.c_str()); -#endif -} - } // namespace sinks } // namespace spdlog