Commit 397d4866 authored by gabime's avatar gabime

Fixed issue #396 and added some tests to catch it

parent 27df6eb4
...@@ -63,6 +63,11 @@ public: ...@@ -63,6 +63,11 @@ public:
//Wait for the queue to be empty, and flush synchronously //Wait for the queue to be empty, and flush synchronously
//Warning: this can potentialy last forever as we wait it to complete //Warning: this can potentialy last forever as we wait it to complete
void flush() override; void flush() override;
// Error handler
virtual void set_error_handler(log_err_handler) override;
virtual log_err_handler error_handler() override;
protected: protected:
void _sink_it(details::log_msg& msg) override; void _sink_it(details::log_msg& msg) override;
void _set_formatter(spdlog::formatter_ptr msg_formatter) override; void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
......
This diff is collapsed.
...@@ -57,6 +57,19 @@ inline void spdlog::async_logger::flush() ...@@ -57,6 +57,19 @@ inline void spdlog::async_logger::flush()
_async_log_helper->flush(true); _async_log_helper->flush(true);
} }
// Error handler
inline void spdlog::async_logger::set_error_handler(spdlog::log_err_handler err_handler)
{
_err_handler = err_handler;
_async_log_helper->set_error_handler(err_handler);
}
inline spdlog::log_err_handler spdlog::async_logger::error_handler()
{
return _err_handler;
}
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
{ {
_formatter = msg_formatter; _formatter = msg_formatter;
......
...@@ -58,11 +58,7 @@ public: ...@@ -58,11 +58,7 @@ public:
const std::string& name() const; const std::string& name() const;
void set_pattern(const std::string&); void set_pattern(const std::string&);
void set_formatter(formatter_ptr); void set_formatter(formatter_ptr);
// error handler
void set_error_handler(log_err_handler);
log_err_handler error_handler();
// automatically call flush() if message level >= log_level // automatically call flush() if message level >= log_level
void flush_on(level::level_enum log_level); void flush_on(level::level_enum log_level);
...@@ -70,6 +66,10 @@ public: ...@@ -70,6 +66,10 @@ public:
const std::vector<sink_ptr>& sinks() const; const std::vector<sink_ptr>& sinks() const;
// error handler
virtual void set_error_handler(log_err_handler);
virtual log_err_handler error_handler();
protected: protected:
virtual void _sink_it(details::log_msg&); virtual void _sink_it(details::log_msg&);
virtual void _set_pattern(const std::string&); virtual void _set_pattern(const std::string&);
......
...@@ -6,59 +6,104 @@ ...@@ -6,59 +6,104 @@
#include<iostream> #include<iostream>
class failing_sink: public spdlog::sinks::sink
{
void log(const spdlog::details::log_msg& msg) override
{
throw std::runtime_error("some error happened during log");
}
void flush()
{}
};
TEST_CASE("default_error_handler", "[errors]]") TEST_CASE("default_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log.txt"; std::string filename = "logs/simple_log.txt";
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
logger->set_pattern("%v"); logger->set_pattern("%v");
logger->info("Test message {} {}", 1); logger->info("Test message {} {}", 1);
logger->info("Test message {}", 2); logger->info("Test message {}", 2);
logger->flush(); logger->flush();
REQUIRE(file_contents(filename) == std::string("Test message 2\n")); REQUIRE(file_contents(filename) == std::string("Test message 2\n"));
REQUIRE(count_lines(filename) == 1); REQUIRE(count_lines(filename) == 1);
} }
struct custom_ex {};
struct custom_ex
{};
TEST_CASE("custom_error_handler", "[errors]]") TEST_CASE("custom_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string filename = "logs/simple_log.txt"; std::string filename = "logs/simple_log.txt";
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::simple_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& msg) logger->set_error_handler([=](const std::string& msg) {
{ throw custom_ex();
throw custom_ex(); });
}); logger->info("Good message #1");
logger->info("Good message #1"); REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex);
REQUIRE_THROWS_AS(logger->info("Bad format msg {} {}", "xxx"), custom_ex); logger->info("Good message #2");
logger->info("Good message #2"); REQUIRE(count_lines(filename) == 2);
REQUIRE(count_lines(filename) == 2); }
TEST_CASE("default_error_handler2", "[errors]]")
{
auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string& msg) {
throw custom_ex();
});
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
} }
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::set_async_mode(128); spdlog::set_async_mode(128);
std::string filename = "logs/simple_async_log.txt"; std::string filename = "logs/simple_async_log.txt";
{ {
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true); auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string& msg) logger->set_error_handler([=](const std::string& msg) {
{ std::ofstream ofs("logs/custom_err.txt");
std::ofstream ofs("logs/custom_err.txt"); if (!ofs) throw std::runtime_error("Failed open logs/custom_err.txt");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err.txt"); ofs << err_msg;
ofs << err_msg; });
}); logger->info("Good message #1");
logger->info("Good message #1"); logger->info("Bad format msg {} {}", "xxx");
logger->info("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::set_sync_mode();
spdlog::set_sync_mode(); }
} REQUIRE(count_lines(filename) == 2);
REQUIRE(count_lines(filename) == 2); REQUIRE(file_contents("logs/custom_err.txt") == err_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::set_async_mode(128);
{
auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string& msg) {
std::ofstream ofs("logs/custom_err2.txt");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err2.txt");
ofs << err_msg;
});
logger->info("Hello failure");
spdlog::drop("failed_logger"); //force logger to drain the queue and shutdown
spdlog::set_sync_mode();
}
REQUIRE(file_contents("logs/custom_err2.txt") == err_msg);
} }
...@@ -4,11 +4,12 @@ void prepare_logdir() ...@@ -4,11 +4,12 @@ void prepare_logdir()
{ {
spdlog::drop_all(); spdlog::drop_all();
#ifdef _WIN32 #ifdef _WIN32
auto rv = system("del /F /Q logs\\*"); system("if not exist logs mkdir logs");
system("del /F /Q logs\\*");
#else #else
auto rv = system("rm -f logs/*"); system("mkdir -p logs");
#endif system("rm -f logs/*");
(void)rv; #endif
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment