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 details
{
namespace details
{
class async_log_helper
{
class async_log_helper
{
// Async msg to move to/from the queue
// Movable only. should never be copied
enum class async_msg_type
@ -58,7 +58,7 @@ namespace spdlog
~async_msg() = default;
async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
logger_name(std::move(other.logger_name)),
level(std::move(other.level)),
time(std::move(other.time)),
@ -109,7 +109,7 @@ namespace spdlog
}
};
public:
public:
using item_type = async_msg;
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);
private:
private:
formatter_ptr _formatter;
std::vector<std::shared_ptr<sinks::sink>> _sinks;
@ -183,8 +183,8 @@ namespace spdlog
// wait until the queue is empty
void wait_empty_q();
};
}
};
}
}
///////////////////////////////////////////////////////////////////////////////
@ -216,7 +216,8 @@ inline spdlog::details::async_log_helper::async_log_helper(
// and wait for it to finish gracefully
inline spdlog::details::async_log_helper::~async_log_helper()
{
try {
try
{
push_msg(async_msg(async_msg_type::terminate));
_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)
{
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 now = last_op_time;
do {
do
{
now = details::os::now();
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_flush = last_pop;
auto active = true;
while (active) {
try {
while (active)
{
try
{
active = process_next_msg(last_pop, last_flush);
}
catch (const std::exception &ex) {
catch (const std::exception &ex)
{
_err_handler(ex.what());
}
catch (...) {
catch (...)
{
_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;
if (_q.dequeue(incoming_async_msg)) {
if (_q.dequeue(incoming_async_msg))
{
last_pop = details::os::now();
switch (incoming_async_msg.msg_type) {
switch (incoming_async_msg.msg_type)
{
case async_msg_type::flush:
_flush_requested = true;
break;
@ -296,8 +306,10 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
log_msg incoming_log_msg;
incoming_async_msg.fill_log_msg(incoming_log_msg);
_formatter->format(incoming_log_msg);
for (auto &s : _sinks) {
if (s->should_log(incoming_log_msg.level)) {
for (auto &s : _sinks)
{
if (s->should_log(incoming_log_msg.level))
{
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..
// 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();
handle_flush_interval(now, last_flush);
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)
{
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)
s->flush();
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()
{
auto last_op = details::os::now();
while (_q.approx_size() > 0) {
while (_q.approx_size() > 0)
{
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 <ostream>
namespace fmt {
namespace fmt
{
namespace internal {
namespace internal
{
template <class Char>
class FormatBuf : public std::basic_streambuf<Char> {
private:
class FormatBuf : public std::basic_streambuf<Char>
{
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_;
Char *start_;
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0])
{
this->setp(start_, start_ + buffer_.capacity());
}
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_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()))
{
size_t buf_size = size();
buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2);
@ -44,14 +50,16 @@ class FormatBuf : public std::basic_streambuf<Char> {
return ch;
}
size_t size() const {
size_t size() const
{
return to_unsigned(this->pptr() - start_);
}
};
Yes &convert(std::ostream &);
struct DummyStream : std::ostream {
struct DummyStream : std::ostream
{
DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
void operator<<(Null<>);
@ -60,9 +68,11 @@ struct DummyStream : std::ostream {
No &operator<<(std::ostream &, int);
template<typename T>
struct ConvertToIntImpl<T, true> {
struct ConvertToIntImpl<T, true>
{
// Convert to int only if T doesn't have an overloaded operator<<.
enum {
enum
{
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
};
};
@ -71,7 +81,8 @@ struct ConvertToIntImpl<T, true> {
// Formats a value.
template <typename Char, typename ArgFormatter, typename T>
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::FormatBuf<Char> format_buf(buffer);

View File

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

View File

@ -13,10 +13,12 @@
#include "format.h"
#include <ctime>
namespace fmt {
namespace fmt
{
template <typename ArgFormatter>
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 == ':')
++format_str;
const char *end = format_str;
@ -29,14 +31,17 @@ void format(BasicFormatter<char, ArgFormatter> &f,
format[format.size() - 1] = '\0';
Buffer<char> &buffer = f.writer().buffer();
std::size_t start = buffer.size();
for (;;) {
for (;;)
{
std::size_t size = buffer.capacity() - start;
std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
if (count != 0) {
if (count != 0)
{
buffer.resize(start + count);
break;
}
if (size >= format.size() * 256) {
if (size >= format.size() * 256)
{
// 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
// 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";
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
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();
});
logger->info("Good message #1");
@ -58,7 +59,8 @@ TEST_CASE("default_error_handler2", "[errors]]")
{
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();
});
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";
{
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");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err.txt");
ofs << err_msg;
@ -95,7 +98,8 @@ TEST_CASE("async_error_handler2", "[errors]]")
spdlog::set_async_mode(128);
{
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");
if (!ofs) throw std::runtime_error("Failed open logs/custom_err2.txt");
ofs << err_msg;