Restored error_handler as std::function
This commit is contained in:
		@@ -49,7 +49,7 @@ endif()
 | 
			
		||||
 | 
			
		||||
option(SPDLOG_HEADER_ONLY "Header only version. Turn OFF to build as static lib" OFF)
 | 
			
		||||
option(SPDLOG_BUILD_EXAMPLES "Build examples" ${SPDLOG_MASTER_PROJECT})
 | 
			
		||||
option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" OFF)
 | 
			
		||||
option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" ON)
 | 
			
		||||
option(SPDLOG_BUILD_TESTS "Build tests" ${SPDLOG_MASTER_PROJECT})
 | 
			
		||||
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
 | 
			
		||||
option(SPDLOG_INSTALL "Generate the install target." ${SPDLOG_MASTER_PROJECT})
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@
 | 
			
		||||
#include "spdlog/async.h"
 | 
			
		||||
#include "spdlog/sinks/stdout_color_sinks.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main(int, char *[])
 | 
			
		||||
{
 | 
			
		||||
    using spdlog::sinks::stderr_color_sink_mt;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,121 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Copyright(c) 2015 Gabi Melman.
 | 
			
		||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
// async logger implementation
 | 
			
		||||
// uses a thread pool to perform the actual logging
 | 
			
		||||
 | 
			
		||||
#include "spdlog/details/thread_pool.h"
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
template<typename It>
 | 
			
		||||
inline spdlog::async_logger::async_logger(
 | 
			
		||||
    std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
 | 
			
		||||
    : logger(std::move(logger_name), begin, end)
 | 
			
		||||
    , thread_pool_(std::move(tp))
 | 
			
		||||
    , overflow_policy_(overflow_policy)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline spdlog::async_logger::async_logger(
 | 
			
		||||
    std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
 | 
			
		||||
    : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline spdlog::async_logger::async_logger(
 | 
			
		||||
    std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
 | 
			
		||||
    : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// send the log message to the thread pool
 | 
			
		||||
inline void spdlog::async_logger::sink_it_(details::log_msg &msg)
 | 
			
		||||
{
 | 
			
		||||
    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");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// send flush request to the thread pool
 | 
			
		||||
inline void spdlog::async_logger::flush_()
 | 
			
		||||
{
 | 
			
		||||
    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");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// backend functions - called from the thread pool to do the actual job
 | 
			
		||||
//
 | 
			
		||||
inline void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg)
 | 
			
		||||
{
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        for (auto &s : sinks_)
 | 
			
		||||
        {
 | 
			
		||||
            if (s->should_log(incoming_log_msg.level))
 | 
			
		||||
            {
 | 
			
		||||
                s->log(incoming_log_msg);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::exception &ex)
 | 
			
		||||
    {
 | 
			
		||||
        err_handler_(ex.what());
 | 
			
		||||
    }
 | 
			
		||||
    catch (...)
 | 
			
		||||
    {
 | 
			
		||||
        err_handler_("Unknown exception in logger");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (should_flush_(incoming_log_msg))
 | 
			
		||||
    {
 | 
			
		||||
        backend_flush_();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void spdlog::async_logger::backend_flush_()
 | 
			
		||||
{
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        for (auto &sink : sinks_)
 | 
			
		||||
        {
 | 
			
		||||
            sink->flush();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::exception &ex)
 | 
			
		||||
    {
 | 
			
		||||
        err_handler_(ex.what());
 | 
			
		||||
    }
 | 
			
		||||
    catch (...)
 | 
			
		||||
    {
 | 
			
		||||
        err_handler_("Unknown exception in logger");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
 | 
			
		||||
{
 | 
			
		||||
    auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_);
 | 
			
		||||
 | 
			
		||||
    cloned->set_level(this->level());
 | 
			
		||||
    cloned->flush_on(this->flush_level());
 | 
			
		||||
    cloned->set_error_handler(this->custom_err_handler_);
 | 
			
		||||
    return std::move(cloned);
 | 
			
		||||
}
 | 
			
		||||
@@ -27,12 +27,13 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
namespace spdlog {
 | 
			
		||||
class logger
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
		using err_handler = void (*)(const std::string &msg);
 | 
			
		||||
        using err_handler = std::function<void(const std::string &err_msg)>;
 | 
			
		||||
        template<typename It>
 | 
			
		||||
        logger(std::string name, It begin, It end)
 | 
			
		||||
            : name_(std::move(name))
 | 
			
		||||
@@ -333,9 +334,6 @@ public:
 | 
			
		||||
        // print the error to stderr with the max rate of 1 message/minute.
 | 
			
		||||
        void err_handler_(const std::string &msg);
 | 
			
		||||
        
 | 
			
		||||
        // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER))
 | 
			
		||||
        void incr_msg_counter_(details::log_msg &msg);
 | 
			
		||||
 | 
			
		||||
        const std::string name_;
 | 
			
		||||
        std::vector<sink_ptr> sinks_;
 | 
			
		||||
        spdlog::level_t level_{spdlog::logger::default_level()};
 | 
			
		||||
 
 | 
			
		||||
@@ -41,18 +41,13 @@ TEST_CASE("default_error_handler", "[errors]]")
 | 
			
		||||
struct custom_ex
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void custom_handler(const std::string &)
 | 
			
		||||
{
 | 
			
		||||
    throw custom_ex();
 | 
			
		||||
}
 | 
			
		||||
TEST_CASE("custom_error_handler", "[errors]]")
 | 
			
		||||
{
 | 
			
		||||
    prepare_logdir();
 | 
			
		||||
    std::string filename = "logs/simple_log.txt";
 | 
			
		||||
    auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
 | 
			
		||||
    logger->flush_on(spdlog::level::info);
 | 
			
		||||
    logger->set_error_handler(custom_handler);
 | 
			
		||||
    logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
 | 
			
		||||
    logger->info("Good message #1");
 | 
			
		||||
 | 
			
		||||
    REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex);
 | 
			
		||||
@@ -64,7 +59,7 @@ TEST_CASE("default_error_handler2", "[errors]]")
 | 
			
		||||
{
 | 
			
		||||
    spdlog::drop_all();
 | 
			
		||||
    auto logger = spdlog::create<failing_sink>("failed_logger");
 | 
			
		||||
    logger->set_error_handler(custom_handler);
 | 
			
		||||
    logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
 | 
			
		||||
    REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -72,26 +67,26 @@ TEST_CASE("flush_error_handler", "[errors]]")
 | 
			
		||||
{
 | 
			
		||||
    spdlog::drop_all();
 | 
			
		||||
    auto logger = spdlog::create<failing_sink>("failed_logger");
 | 
			
		||||
    logger->set_error_handler(custom_handler);
 | 
			
		||||
    logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
 | 
			
		||||
    REQUIRE_THROWS_AS(logger->flush(), custom_ex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("async_error_handler", "[errors]]")
 | 
			
		||||
{
 | 
			
		||||
    prepare_logdir();
 | 
			
		||||
    
 | 
			
		||||
    std::string err_msg("log failed with some msg");
 | 
			
		||||
 | 
			
		||||
    std::string filename = "logs/simple_async_log.txt";
 | 
			
		||||
    {
 | 
			
		||||
        spdlog::init_thread_pool(128, 1);
 | 
			
		||||
        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("logs/custom_err.txt");
 | 
			
		||||
            if (!ofs)
 | 
			
		||||
            {
 | 
			
		||||
                throw std::runtime_error("Failed open logs/custom_err.txt");
 | 
			
		||||
            }
 | 
			
		||||
            ofs << "log failed with some msg";
 | 
			
		||||
            ofs << err_msg;
 | 
			
		||||
        });
 | 
			
		||||
        logger->info("Good message #1");
 | 
			
		||||
        logger->info("Bad format msg {} {}", "xxx");
 | 
			
		||||
@@ -100,26 +95,27 @@ TEST_CASE("async_error_handler", "[errors]]")
 | 
			
		||||
    }
 | 
			
		||||
    spdlog::init_thread_pool(128, 1);
 | 
			
		||||
    REQUIRE(count_lines(filename) == 2);
 | 
			
		||||
    REQUIRE(file_contents("logs/custom_err.txt") == "log failed with some msg");
 | 
			
		||||
    REQUIRE(file_contents("logs/custom_err.txt") == err_msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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::init_thread_pool(128, 1);
 | 
			
		||||
        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("logs/custom_err2.txt");
 | 
			
		||||
            if (!ofs)
 | 
			
		||||
                throw std::runtime_error("Failed open logs/custom_err2.txt");
 | 
			
		||||
            ofs << "handler error message";
 | 
			
		||||
            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("logs/custom_err2.txt") == "handler error message");
 | 
			
		||||
    REQUIRE(file_contents("logs/custom_err2.txt") == err_msg);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user