This commit is contained in:
gabime 2017-03-28 02:08:18 +03:00
parent 5a8cecdfb6
commit 0c276beaaf
10 changed files with 3414 additions and 2704 deletions

View File

@ -32,11 +32,11 @@
namespace spdlog namespace spdlog
{ {
namespace details namespace details
{ {
class async_log_helper class async_log_helper
{ {
// Async msg to move to/from the queue // Async msg to move to/from the queue
// Movable only. should never be copied // Movable only. should never be copied
enum class async_msg_type enum class async_msg_type
@ -58,7 +58,7 @@ namespace spdlog
~async_msg() = default; ~async_msg() = default;
async_msg(async_msg&& other) SPDLOG_NOEXCEPT: async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
logger_name(std::move(other.logger_name)), logger_name(std::move(other.logger_name)),
level(std::move(other.level)), level(std::move(other.level)),
time(std::move(other.time)), time(std::move(other.time)),
@ -109,7 +109,7 @@ namespace spdlog
} }
}; };
public: public:
using item_type = async_msg; using item_type = async_msg;
using q_type = details::mpmc_bounded_queue<item_type>; using q_type = details::mpmc_bounded_queue<item_type>;
@ -137,7 +137,7 @@ namespace spdlog
void set_error_handler(spdlog::log_err_handler err_handler); void set_error_handler(spdlog::log_err_handler err_handler);
private: private:
formatter_ptr _formatter; formatter_ptr _formatter;
std::vector<std::shared_ptr<sinks::sink>> _sinks; std::vector<std::shared_ptr<sinks::sink>> _sinks;
@ -183,8 +183,8 @@ namespace spdlog
// wait until the queue is empty // wait until the queue is empty
void wait_empty_q(); void wait_empty_q();
}; };
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -216,7 +216,8 @@ inline spdlog::details::async_log_helper::async_log_helper(
// and wait for it to finish gracefully // and wait for it to finish gracefully
inline spdlog::details::async_log_helper::~async_log_helper() inline spdlog::details::async_log_helper::~async_log_helper()
{ {
try { try
{
push_msg(async_msg(async_msg_type::terminate)); push_msg(async_msg(async_msg_type::terminate));
_worker_thread.join(); _worker_thread.join();
} }
@ -234,13 +235,16 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
{ {
if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg) { if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
{
auto last_op_time = details::os::now(); auto last_op_time = details::os::now();
auto now = last_op_time; auto now = last_op_time;
do { do
{
now = details::os::now(); now = details::os::now();
sleep_or_yield(now, last_op_time); sleep_or_yield(now, last_op_time);
} while (!_q.enqueue(std::move(new_msg))); }
while (!_q.enqueue(std::move(new_msg)));
} }
} }
@ -258,14 +262,18 @@ inline void spdlog::details::async_log_helper::worker_loop()
auto last_pop = details::os::now(); auto last_pop = details::os::now();
auto last_flush = last_pop; auto last_flush = last_pop;
auto active = true; auto active = true;
while (active) { while (active)
try { {
try
{
active = process_next_msg(last_pop, last_flush); active = process_next_msg(last_pop, last_flush);
} }
catch (const std::exception &ex) { catch (const std::exception &ex)
{
_err_handler(ex.what()); _err_handler(ex.what());
} }
catch (...) { catch (...)
{
_err_handler("Unknown exception"); _err_handler("Unknown exception");
} }
} }
@ -280,9 +288,11 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
{ {
async_msg incoming_async_msg; async_msg incoming_async_msg;
if (_q.dequeue(incoming_async_msg)) { if (_q.dequeue(incoming_async_msg))
{
last_pop = details::os::now(); last_pop = details::os::now();
switch (incoming_async_msg.msg_type) { switch (incoming_async_msg.msg_type)
{
case async_msg_type::flush: case async_msg_type::flush:
_flush_requested = true; _flush_requested = true;
break; break;
@ -296,8 +306,10 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
log_msg incoming_log_msg; log_msg incoming_log_msg;
incoming_async_msg.fill_log_msg(incoming_log_msg); incoming_async_msg.fill_log_msg(incoming_log_msg);
_formatter->format(incoming_log_msg); _formatter->format(incoming_log_msg);
for (auto &s : _sinks) { for (auto &s : _sinks)
if (s->should_log(incoming_log_msg.level)) { {
if (s->should_log(incoming_log_msg.level))
{
s->log(incoming_log_msg); s->log(incoming_log_msg);
} }
} }
@ -307,7 +319,8 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
// Handle empty queue.. // Handle empty queue..
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue // This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
else { else
{
auto now = details::os::now(); auto now = details::os::now();
handle_flush_interval(now, last_flush); handle_flush_interval(now, last_flush);
sleep_or_yield(now, last_pop); sleep_or_yield(now, last_pop);
@ -319,7 +332,8 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush) inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
{ {
auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms); auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms);
if (should_flush) { if (should_flush)
{
for (auto &s : _sinks) for (auto &s : _sinks)
s->flush(); s->flush();
now = last_flush = details::os::now(); now = last_flush = details::os::now();
@ -362,7 +376,8 @@ inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_
inline void spdlog::details::async_log_helper::wait_empty_q() inline void spdlog::details::async_log_helper::wait_empty_q()
{ {
auto last_op = details::os::now(); auto last_op = details::os::now();
while (_q.approx_size() > 0) { while (_q.approx_size() > 0)
{
sleep_or_yield(details::os::now(), last_op); sleep_or_yield(details::os::now(), last_op);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -13,26 +13,32 @@
#include "format.h" #include "format.h"
#include <ostream> #include <ostream>
namespace fmt { namespace fmt
{
namespace internal { namespace internal
{
template <class Char> template <class Char>
class FormatBuf : public std::basic_streambuf<Char> { class FormatBuf : public std::basic_streambuf<Char>
private: {
private:
typedef typename std::basic_streambuf<Char>::int_type int_type; typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type; typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_; Buffer<Char> &buffer_;
Char *start_; Char *start_;
public: public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) { FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0])
{
this->setp(start_, start_ + buffer_.capacity()); this->setp(start_, start_ + buffer_.capacity());
} }
int_type overflow(int_type ch = traits_type::eof()) { int_type overflow(int_type ch = traits_type::eof())
if (!traits_type::eq_int_type(ch, traits_type::eof())) { {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
{
size_t buf_size = size(); size_t buf_size = size();
buffer_.resize(buf_size); buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2); buffer_.reserve(buf_size * 2);
@ -44,14 +50,16 @@ class FormatBuf : public std::basic_streambuf<Char> {
return ch; return ch;
} }
size_t size() const { size_t size() const
{
return to_unsigned(this->pptr() - start_); return to_unsigned(this->pptr() - start_);
} }
}; };
Yes &convert(std::ostream &); Yes &convert(std::ostream &);
struct DummyStream : std::ostream { struct DummyStream : std::ostream
{
DummyStream(); // Suppress a bogus warning in MSVC. DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream. // Hide all operator<< overloads from std::ostream.
void operator<<(Null<>); void operator<<(Null<>);
@ -60,9 +68,11 @@ struct DummyStream : std::ostream {
No &operator<<(std::ostream &, int); No &operator<<(std::ostream &, int);
template<typename T> template<typename T>
struct ConvertToIntImpl<T, true> { struct ConvertToIntImpl<T, true>
{
// Convert to int only if T doesn't have an overloaded operator<<. // Convert to int only if T doesn't have an overloaded operator<<.
enum { enum
{
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No) value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
}; };
}; };
@ -71,7 +81,8 @@ struct ConvertToIntImpl<T, true> {
// Formats a value. // Formats a value.
template <typename Char, typename ArgFormatter, typename T> template <typename Char, typename ArgFormatter, typename T>
void format(BasicFormatter<Char, ArgFormatter> &f, void format(BasicFormatter<Char, ArgFormatter> &f,
const Char *&format_str, const T &value) { const Char *&format_str, const T &value)
{
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer); internal::FormatBuf<Char> format_buf(buffer);

View File

@ -83,31 +83,39 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt { namespace fmt
{
// An error code. // An error code.
class ErrorCode { class ErrorCode
private: {
private:
int value_; int value_;
public: public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {} explicit ErrorCode(int value = 0) FMT_NOEXCEPT :
value_(value) {}
int get() const FMT_NOEXCEPT { return value_; } int get() const FMT_NOEXCEPT
{
return value_;
}
}; };
// A buffered file. // A buffered file.
class BufferedFile { class BufferedFile
private: {
private:
FILE *file_; FILE *file_;
friend class File; friend class File;
explicit BufferedFile(FILE *f) : file_(f) {} explicit BufferedFile(FILE *f) : file_(f) {}
public: public:
// Constructs a BufferedFile object which doesn't represent any file. // Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : file_(0) {} BufferedFile() FMT_NOEXCEPT :
file_(0) {}
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
~BufferedFile() FMT_NOEXCEPT; ~BufferedFile() FMT_NOEXCEPT;
@ -116,31 +124,37 @@ class BufferedFile {
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
// references are not supported. // references are not supported.
private: private:
// A proxy object to emulate a move constructor. // A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly. // It is private to make it impossible call operator Proxy directly.
struct Proxy { struct Proxy
{
FILE *file; FILE *file;
}; };
public: public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} BufferedFile(Proxy p) FMT_NOEXCEPT :
file_(p.file) {}
// A "move constructor" for moving from an lvalue. // A "move constructor" for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { BufferedFile(BufferedFile &f) FMT_NOEXCEPT :
file_(f.file_)
{
f.file_ = 0; f.file_ = 0;
} }
// A "move assignment operator" for moving from a temporary. // A "move assignment operator" for moving from a temporary.
BufferedFile &operator=(Proxy p) { BufferedFile &operator=(Proxy p)
{
close(); close();
file_ = p.file; file_ = p.file;
return *this; return *this;
} }
// A "move assignment operator" for moving from an lvalue. // A "move assignment operator" for moving from an lvalue.
BufferedFile &operator=(BufferedFile &other) { BufferedFile &operator=(BufferedFile &other)
{
close(); close();
file_ = other.file_; file_ = other.file_;
other.file_ = 0; other.file_ = 0;
@ -149,22 +163,26 @@ public:
// Returns a proxy object for moving from a temporary: // Returns a proxy object for moving from a temporary:
// BufferedFile file = BufferedFile(...); // BufferedFile file = BufferedFile(...);
operator Proxy() FMT_NOEXCEPT { operator Proxy() FMT_NOEXCEPT
{
Proxy p = {file_}; Proxy p = {file_};
file_ = 0; file_ = 0;
return p; return p;
} }
#else #else
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public: public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { BufferedFile(BufferedFile &&other) FMT_NOEXCEPT :
file_(other.file_)
{
other.file_ = 0; other.file_ = 0;
} }
BufferedFile& operator=(BufferedFile &&other) { BufferedFile& operator=(BufferedFile &&other)
{
close(); close();
file_ = other.file_; file_ = other.file_;
other.file_ = 0; other.file_ = 0;
@ -179,13 +197,17 @@ public:
void close(); void close();
// Returns the pointer to a FILE object representing this file. // Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; } FILE *get() const FMT_NOEXCEPT
{
return file_;
}
// We place parentheses around fileno to workaround a bug in some versions // We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro. // of MinGW that define fileno as a macro.
int (fileno)() const; int (fileno)() const;
void print(CStringRef format_str, const ArgList &args) { void print(CStringRef format_str, const ArgList &args)
{
fmt::print(file_, format_str, args); fmt::print(file_, format_str, args);
} }
FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, CStringRef)
@ -197,23 +219,26 @@ public:
// closing the file multiple times will cause a crash on Windows rather // closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the // than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler. // invalid parameter handler with _set_invalid_parameter_handler.
class File { class File
private: {
private:
int fd_; // File descriptor. int fd_; // File descriptor.
// Constructs a File object with a given descriptor. // Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {} explicit File(int fd) : fd_(fd) {}
public: public:
// Possible values for the oflag argument to the constructor. // Possible values for the oflag argument to the constructor.
enum { enum
{
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
}; };
// Constructs a File object which doesn't represent any file. // Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : fd_(-1) {} File() FMT_NOEXCEPT :
fd_(-1) {}
// Opens a file and constructs a File object representing this file. // Opens a file and constructs a File object representing this file.
File(CStringRef path, int oflag); File(CStringRef path, int oflag);
@ -222,31 +247,37 @@ class File {
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
// references are not supported. // references are not supported.
private: private:
// A proxy object to emulate a move constructor. // A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly. // It is private to make it impossible call operator Proxy directly.
struct Proxy { struct Proxy
{
int fd; int fd;
}; };
public: public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} File(Proxy p) FMT_NOEXCEPT :
fd_(p.fd) {}
// A "move constructor" for moving from an lvalue. // A "move constructor" for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { File(File &other) FMT_NOEXCEPT :
fd_(other.fd_)
{
other.fd_ = -1; other.fd_ = -1;
} }
// A "move assignment operator" for moving from a temporary. // A "move assignment operator" for moving from a temporary.
File &operator=(Proxy p) { File &operator=(Proxy p)
{
close(); close();
fd_ = p.fd; fd_ = p.fd;
return *this; return *this;
} }
// A "move assignment operator" for moving from an lvalue. // A "move assignment operator" for moving from an lvalue.
File &operator=(File &other) { File &operator=(File &other)
{
close(); close();
fd_ = other.fd_; fd_ = other.fd_;
other.fd_ = -1; other.fd_ = -1;
@ -255,22 +286,26 @@ class File {
// Returns a proxy object for moving from a temporary: // Returns a proxy object for moving from a temporary:
// File file = File(...); // File file = File(...);
operator Proxy() FMT_NOEXCEPT { operator Proxy() FMT_NOEXCEPT
{
Proxy p = {fd_}; Proxy p = {fd_};
fd_ = -1; fd_ = -1;
return p; return p;
} }
#else #else
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(File); FMT_DISALLOW_COPY_AND_ASSIGN(File);
public: public:
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) { File(File &&other) FMT_NOEXCEPT :
fd_(other.fd_)
{
other.fd_ = -1; other.fd_ = -1;
} }
File& operator=(File &&other) { File& operator=(File &&other)
{
close(); close();
fd_ = other.fd_; fd_ = other.fd_;
other.fd_ = -1; other.fd_ = -1;
@ -282,7 +317,10 @@ class File {
~File() FMT_NOEXCEPT; ~File() FMT_NOEXCEPT;
// Returns the file descriptor. // Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; } int descriptor() const FMT_NOEXCEPT
{
return fd_;
}
// Closes the file. // Closes the file.
void close(); void close();
@ -328,22 +366,26 @@ long getpagesize();
#ifdef FMT_LOCALE #ifdef FMT_LOCALE
// A "C" numeric locale. // A "C" numeric locale.
class Locale { class Locale
private: {
private:
# ifdef _MSC_VER # ifdef _MSC_VER
typedef _locale_t locale_t; typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC }; enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char *locale, locale_t) { static locale_t newlocale(int category_mask, const char *locale, locale_t)
{
return _create_locale(category_mask, locale); return _create_locale(category_mask, locale);
} }
static void freelocale(locale_t locale) { static void freelocale(locale_t locale)
{
_free_locale(locale); _free_locale(locale);
} }
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { static double strtod_l(const char *nptr, char **endptr, _locale_t locale)
{
return _strtod_l(nptr, endptr, locale); return _strtod_l(nptr, endptr, locale);
} }
# endif # endif
@ -352,20 +394,28 @@ class Locale {
FMT_DISALLOW_COPY_AND_ASSIGN(Locale); FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
public: public:
typedef locale_t Type; typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL))
{
if (!locale_) if (!locale_)
FMT_THROW(fmt::SystemError(errno, "cannot create locale")); FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
} }
~Locale() { freelocale(locale_); } ~Locale()
{
freelocale(locale_);
}
Type get() const { return locale_; } Type get() const
{
return locale_;
}
// Converts string to floating-point number and advances str past the end // Converts string to floating-point number and advances str past the end
// of the parsed input. // of the parsed input.
double strtod(const char *&str) const { double strtod(const char *&str) const
{
char *end = 0; char *end = 0;
double result = strtod_l(str, &end, locale_); double result = strtod_l(str, &end, locale_);
str = end; str = end;
@ -376,10 +426,17 @@ class Locale {
} // namespace fmt } // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
namespace std { namespace std
{
// For compatibility with C++98. // For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; } inline fmt::BufferedFile &move(fmt::BufferedFile &f)
inline fmt::File &move(fmt::File &f) { return f; } {
return f;
}
inline fmt::File &move(fmt::File &f)
{
return f;
}
} }
#endif #endif

View File

@ -13,10 +13,12 @@
#include "format.h" #include "format.h"
#include <ctime> #include <ctime>
namespace fmt { namespace fmt
{
template <typename ArgFormatter> template <typename ArgFormatter>
void format(BasicFormatter<char, ArgFormatter> &f, void format(BasicFormatter<char, ArgFormatter> &f,
const char *&format_str, const std::tm &tm) { const char *&format_str, const std::tm &tm)
{
if (*format_str == ':') if (*format_str == ':')
++format_str; ++format_str;
const char *end = format_str; const char *end = format_str;
@ -29,14 +31,17 @@ void format(BasicFormatter<char, ArgFormatter> &f,
format[format.size() - 1] = '\0'; format[format.size() - 1] = '\0';
Buffer<char> &buffer = f.writer().buffer(); Buffer<char> &buffer = f.writer().buffer();
std::size_t start = buffer.size(); std::size_t start = buffer.size();
for (;;) { for (;;)
{
std::size_t size = buffer.capacity() - start; std::size_t size = buffer.capacity() - start;
std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
if (count != 0) { if (count != 0)
{
buffer.resize(start + count); buffer.resize(start + count);
break; break;
} }
if (size >= format.size() * 256) { if (size >= format.size() * 256)
{
// If the buffer is 256 times larger than the format string, assume // If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a // that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases: // better way to distinguish the two cases:

View File

@ -45,7 +45,8 @@ TEST_CASE("custom_error_handler", "[errors]]")
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");
@ -58,7 +59,8 @@ TEST_CASE("default_error_handler2", "[errors]]")
{ {
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string& msg) { logger->set_error_handler([=](const std::string& msg)
{
throw custom_ex(); throw custom_ex();
}); });
REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex);
@ -72,7 +74,8 @@ TEST_CASE("async_error_handler", "[errors]]")
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;
@ -95,7 +98,8 @@ TEST_CASE("async_error_handler2", "[errors]]")
spdlog::set_async_mode(128); spdlog::set_async_mode(128);
{ {
auto logger = spdlog::create<failing_sink>("failed_logger"); auto logger = spdlog::create<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string& msg) { logger->set_error_handler([=](const std::string& msg)
{
std::ofstream ofs("logs/custom_err2.txt"); std::ofstream ofs("logs/custom_err2.txt");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err2.txt"); if (!ofs) throw std::runtime_error("Failed open logs/custom_err2.txt");
ofs << err_msg; ofs << err_msg;