(third_party deps) fix #177, update bundled spdlog to 1.6.0

This commit is contained in:
Benjamin Sergeant
2020-04-11 13:31:39 -07:00
parent 2eb5c9480e
commit f1c106728b
109 changed files with 2792 additions and 689 deletions

View File

@@ -15,7 +15,7 @@
namespace spdlog {
namespace details {
class backtracer
class SPDLOG_API backtracer
{
mutable std::mutex mutex_;
std::atomic<bool> enabled_{false};

View File

@@ -43,14 +43,14 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
details::os::sleep_for_millis(open_interval_);
}
SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno));
throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno);
}
SPDLOG_INLINE void file_helper::reopen(bool truncate)
{
if (filename_.empty())
{
SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before"));
throw_spdlog_ex("Failed re opening file - was not opened before");
}
this->open(filename_, truncate);
}
@@ -75,7 +75,7 @@ SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf)
auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
{
SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno));
throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno);
}
}
@@ -83,7 +83,7 @@ SPDLOG_INLINE size_t file_helper::size() const
{
if (fd_ == nullptr)
{
SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)));
throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_));
}
return os::filesize(fd_);
}

View File

@@ -13,7 +13,7 @@ namespace details {
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
// Throw spdlog_ex exception on errors.
class file_helper
class SPDLOG_API file_helper
{
public:
explicit file_helper() = default;

View File

@@ -20,10 +20,7 @@ inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEX
inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest)
{
auto *buf_ptr = view.data();
if (buf_ptr != nullptr)
{
dest.append(buf_ptr, buf_ptr + view.size());
}
dest.append(buf_ptr, buf_ptr + view.size());
}
template<typename T>
@@ -34,10 +31,10 @@ inline void append_int(T n, memory_buf_t &dest)
}
template<typename T>
inline unsigned count_digits(T n)
inline unsigned int count_digits(T n)
{
using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n)));
return static_cast<unsigned int>(fmt::internal::count_digits(static_cast<count_type>(n)));
}
inline void pad2(int n, memory_buf_t &dest)
@@ -66,11 +63,9 @@ template<typename T>
inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
{
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
auto digits = count_digits(n);
if (width > digits)
for (auto digits = count_digits(n); digits < width; digits++)
{
const char *zeroes = "0000000000000000000";
dest.append(zeroes, zeroes + width - digits);
dest.push_back('0');
}
append_int(n, dest);
}
@@ -78,7 +73,18 @@ inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
template<typename T>
inline void pad3(T n, memory_buf_t &dest)
{
pad_uint(n, 3, dest);
static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T");
if(n < 1000)
{
dest.push_back(static_cast<char>(n / 100 + '0'));
n = n % 100;
dest.push_back(static_cast<char>((n / 10) + '0'));
dest.push_back(static_cast<char>((n % 10) + '0'));
}
else
{
append_int(n, dest);
}
}
template<typename T>

View File

@@ -8,7 +8,7 @@
namespace spdlog {
namespace details {
struct log_msg
struct SPDLOG_API log_msg
{
log_msg() = default;
log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);

View File

@@ -11,7 +11,7 @@ namespace details {
// Extend log_msg with internal buffer to store its payload.
// THis is needed since log_msg holds string_views that points to stack data.
class log_msg_buffer : public log_msg
class SPDLOG_API log_msg_buffer : public log_msg
{
memory_buf_t buffer;
void update_string_views();

View File

@@ -23,16 +23,9 @@
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <io.h> // _get_osfhandle and _isatty support
#include <process.h> // _get_pid support
#include <windows.h>
#include <spdlog/details/windows_include.h>
#ifdef __MINGW32__
#include <share.h>
@@ -126,23 +119,6 @@ SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
return gmtime(now_t);
}
#ifdef SPDLOG_PREVENT_CHILD_FD
SPDLOG_INLINE void prevent_child_fd(FILE *f)
{
#ifdef _WIN32
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(f)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno));
#else
auto fd = ::fileno(f);
if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
{
SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno));
}
#endif
}
#endif // SPDLOG_PREVENT_CHILD_FD
// fopen_s on non windows for writing
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
{
@@ -152,17 +128,35 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename
#else
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif
#else // unix
*fp = ::fopen((filename.c_str()), mode.c_str());
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
// prevent child processes from inheriting log file descriptors
#if defined(SPDLOG_PREVENT_CHILD_FD)
if (*fp != nullptr)
{
prevent_child_fd(*fp);
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
{
::fclose(*fp);
*fp = nullptr;
}
}
#endif
#else // unix
#if defined(SPDLOG_PREVENT_CHILD_FD)
const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
if (fd == -1)
{
return false;
}
*fp = ::fdopen(fd, mode.c_str());
if (*fp == nullptr)
{
::close(fd);
}
#else
*fp = ::fopen((filename.c_str()), mode.c_str());
#endif
#endif
return *fp == nullptr;
}
@@ -210,7 +204,7 @@ SPDLOG_INLINE size_t filesize(FILE *f)
{
if (f == nullptr)
{
SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null"));
throw_spdlog_ex("Failed getting file size. fd is null");
}
#if defined(_WIN32) && !defined(__CYGWIN__)
int fd = ::_fileno(f);
@@ -251,7 +245,8 @@ SPDLOG_INLINE size_t filesize(FILE *f)
}
#endif
#endif
SPDLOG_THROW(spdlog_ex("Failed getting file size from fd", errno));
throw_spdlog_ex("Failed getting file size from fd", errno);
return 0; // will not be reached.
}
// Return utc offset in minutes or throw spdlog_ex on failure
@@ -267,7 +262,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
#endif
if (rv == TIME_ZONE_ID_INVALID)
SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno));
throw_spdlog_ex("Failed getting timezone info. ", errno);
int offset = -tzinfo.Bias;
if (tm.tm_isdst)
@@ -396,13 +391,13 @@ SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
}
// Determine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/
// Based on: https://github.com/agauniyal/rang/
SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return true;
#else
static constexpr std::array<const char *, 14> Terms = {
static constexpr std::array<const char *, 14> terms = {
{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}};
const char *env_p = std::getenv("TERM");
@@ -412,7 +407,7 @@ SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
}
static const bool result =
std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
return result;
#endif
}
@@ -434,7 +429,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
{
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()))
{
SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8"));
throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
}
int wstr_size = static_cast<int>(wstr.size());
@@ -462,7 +457,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
}
}
SPDLOG_THROW(spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())));
throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}
#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
@@ -536,6 +531,24 @@ SPDLOG_INLINE filename_t dir_name(filename_t path)
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
}
std::string SPDLOG_INLINE getenv(const char *field)
{
#if defined(_MSC_VER)
#if defined(__cplusplus_winrt)
return std::string{}; // not supported under uwp
#else
size_t len = 0;
char buf[128];
bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
return ok ? buf : std::string{};
#endif
#else // revert to getenv
char *buf = ::getenv(field);
return buf ? buf : std::string{};
#endif
}
} // namespace os
} // namespace details
} // namespace spdlog

View File

@@ -10,15 +10,15 @@ namespace spdlog {
namespace details {
namespace os {
spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;
SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;
std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
std::tm localtime() SPDLOG_NOEXCEPT;
SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT;
std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
std::tm gmtime() SPDLOG_NOEXCEPT;
SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT;
// eol definition
#if !defined(SPDLOG_EOL)
@@ -38,54 +38,50 @@ static const char folder_sep = '\\';
SPDLOG_CONSTEXPR static const char folder_sep = '/';
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
void prevent_child_fd(FILE *f);
#endif
// fopen_s on non windows for writing
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
// Remove filename. return 0 on success
int remove(const filename_t &filename) SPDLOG_NOEXCEPT;
SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT;
// Remove file if exists. return 0 on success
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
// Return if file exists.
bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
// Return file size according to open FILE* object
size_t filesize(FILE *f);
SPDLOG_API size_t filesize(FILE *f);
// Return utc offset in minutes or throw spdlog_ex on failure
int utc_minutes_offset(const std::tm &tm = details::os::localtime());
SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime());
// Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013)
size_t _thread_id() SPDLOG_NOEXCEPT;
SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT;
// Return current thread id as size_t (from thread local storage)
size_t thread_id() SPDLOG_NOEXCEPT;
SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT;
// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT;
SPDLOG_API void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT;
std::string filename_to_str(const filename_t &filename);
SPDLOG_API std::string filename_to_str(const filename_t &filename);
int pid() SPDLOG_NOEXCEPT;
SPDLOG_API int pid() SPDLOG_NOEXCEPT;
// Determine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/
bool is_color_terminal() SPDLOG_NOEXCEPT;
SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT;
// Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/
bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
@@ -96,11 +92,15 @@ void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
// "abc/" => "abc"
// "abc" => ""
// "abc///" => "abc//"
filename_t dir_name(filename_t path);
SPDLOG_API filename_t dir_name(filename_t path);
// Create a dir from the given path.
// Return true if succeeded or if this dir already exists.
bool create_dir(filename_t path);
SPDLOG_API bool create_dir(filename_t path);
// non thread safe, cross platform getenv/getenv_s
// return empty string if field not found
SPDLOG_API std::string getenv(const char *field);
} // namespace os
} // namespace details

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/formatter.h>
#include <chrono>
#include <ctime>
#include <memory>
#include <string>
#include <vector>
namespace spdlog {
namespace details {
// padding information.
struct padding_info
{
enum pad_side
{
left,
right,
center
};
padding_info() = default;
padding_info(size_t width, padding_info::pad_side side, bool truncate)
: width_(width)
, side_(side)
, truncate_(truncate)
, enabled_(true)
{}
bool enabled() const
{
return enabled_;
}
const size_t width_ = 0;
const pad_side side_ = left;
bool truncate_ = false;
bool enabled_ = false;
};
class flag_formatter
{
public:
explicit flag_formatter(padding_info padinfo)
: padinfo_(padinfo)
{}
flag_formatter() = default;
virtual ~flag_formatter() = default;
virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0;
protected:
padding_info padinfo_;
};
} // namespace details
class pattern_formatter final : public formatter
{
public:
explicit pattern_formatter(
std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
// use default pattern is not given
explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
pattern_formatter(const pattern_formatter &other) = delete;
pattern_formatter &operator=(const pattern_formatter &other) = delete;
std::unique_ptr<formatter> clone() const override;
void format(const details::log_msg &msg, memory_buf_t &dest) override;
private:
std::string pattern_;
std::string eol_;
pattern_time_type pattern_time_type_;
std::tm cached_tm_;
std::chrono::seconds last_log_secs_;
std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
std::tm get_time_(const details::log_msg &msg);
template<typename Padder>
void handle_flag_(char flag, details::padding_info padding);
// Extract given pad spec (e.g. %8X)
// Advance the given it pass the end of the padding spec found (if any)
// Return padding.
details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
void compile_pattern_(const std::string &pattern);
};
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "pattern_formatter-inl.h"
#endif

View File

@@ -17,7 +17,7 @@
namespace spdlog {
namespace details {
class periodic_worker
class SPDLOG_API periodic_worker
{
public:
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);

View File

@@ -10,7 +10,7 @@
#include <spdlog/common.h>
#include <spdlog/details/periodic_worker.h>
#include <spdlog/logger.h>
#include <spdlog/details/pattern_formatter.h>
#include <spdlog/pattern_formatter.h>
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
// support for the default stdout color logger
@@ -48,6 +48,9 @@ SPDLOG_INLINE registry::registry()
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
}
SPDLOG_INLINE registry::~registry() = default;
SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
@@ -64,7 +67,7 @@ SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logge
new_logger->set_error_handler(err_handler_);
}
new_logger->set_level(level_);
new_logger->set_level(levels_.get(new_logger->name()));
new_logger->flush_on(flush_level_);
if (backtrace_n_messages_ > 0)
@@ -168,7 +171,7 @@ SPDLOG_INLINE void registry::set_level(level::level_enum log_level)
{
l.second->set_level(log_level);
}
level_ = log_level;
levels_.set_default(log_level);
}
SPDLOG_INLINE void registry::flush_on(level::level_enum log_level)
@@ -184,7 +187,7 @@ SPDLOG_INLINE void registry::flush_on(level::level_enum log_level)
SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)
{
std::lock_guard<std::mutex> lock(flusher_mutex_);
std::function<void()> clbk = std::bind(&registry::flush_all, this);
auto clbk = [this]() { this->flush_all(); };
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
}
@@ -260,6 +263,17 @@ SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registrat
automatic_registration_ = automatic_registration;
}
SPDLOG_INLINE void registry::update_levels(cfg::log_levels levels)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
levels_ = std::move(levels);
for (auto &l : loggers_)
{
auto &logger = l.second;
logger->set_level(levels_.get(logger->name()));
}
}
SPDLOG_INLINE registry &registry::instance()
{
static registry s_instance;
@@ -270,7 +284,7 @@ SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)
{
if (loggers_.find(logger_name) != loggers_.end())
{
SPDLOG_THROW(spdlog_ex("logger with name '" + logger_name + "' already exists"));
throw_spdlog_ex("logger with name '" + logger_name + "' already exists");
}
}
@@ -280,5 +294,6 @@ SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger
throw_if_exists_(logger_name);
loggers_[logger_name] = std::move(new_logger);
}
} // namespace details
} // namespace spdlog

View File

@@ -9,6 +9,7 @@
// This class is thread safe
#include <spdlog/common.h>
#include <spdlog/cfg/log_levels.h>
#include <chrono>
#include <functional>
@@ -24,7 +25,7 @@ namespace details {
class thread_pool;
class periodic_worker;
class registry
class SPDLOG_API registry
{
public:
registry(const registry &) = delete;
@@ -79,19 +80,21 @@ public:
void set_automatic_registration(bool automatic_registration);
void update_levels(cfg::log_levels levels);
static registry &instance();
private:
registry();
~registry() = default;
~registry();
void throw_if_exists_(const std::string &logger_name);
void register_logger_(std::shared_ptr<logger> new_logger);
std::mutex logger_map_mutex_, flusher_mutex_;
std::recursive_mutex tp_mutex_;
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
cfg::log_levels levels_;
std::unique_ptr<formatter> formatter_;
level::level_enum level_ = level::info;
level::level_enum flush_level_ = level::off;
void (*err_handler_)(const std::string &msg);
std::shared_ptr<thread_pool> tp_;

View File

@@ -0,0 +1,175 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#define WIN32_LEAN_AND_MEAN
// tcp client helper
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
#pragma comment(lib, "AdvApi32.lib")
namespace spdlog {
namespace details {
class tcp_client
{
SOCKET socket_ = INVALID_SOCKET;
static bool winsock_initialized_()
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
return false;
}
else
{
closesocket(s);
return true;
}
}
static void init_winsock_()
{
WSADATA wsaData;
auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rv != 0)
{
throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
}
}
static void throw_winsock_error_(const std::string &msg, int last_error)
{
char buf[512];
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf));
}
public:
bool is_connected() const
{
return socket_ != INVALID_SOCKET;
}
void close()
{
::closesocket(socket_);
socket_ = INVALID_SOCKET;
WSACleanup();
}
SOCKET fd() const
{
return socket_;
}
~tcp_client()
{
close();
}
// try to connect or throw on failure
void connect(const std::string &host, int port)
{
// initialize winsock if needed
if (!winsock_initialized_())
{
init_winsock_();
}
if (is_connected())
{
close();
}
struct addrinfo hints
{};
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
hints.ai_protocol = 0;
auto port_str = std::to_string(port);
struct addrinfo *addrinfo_result;
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
int last_error = 0;
if (rv != 0)
{
last_error = ::WSAGetLastError();
WSACleanup();
throw_winsock_error_("getaddrinfo failed", last_error);
}
// Try each address until we successfully connect(2).
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
{
socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (socket_ == INVALID_SOCKET)
{
last_error = ::WSAGetLastError();
WSACleanup();
continue;
}
if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0)
{
break;
}
else
{
last_error = ::WSAGetLastError();
close();
}
}
::freeaddrinfo(addrinfo_result);
if (socket_ == INVALID_SOCKET)
{
WSACleanup();
throw_winsock_error_("connect failed", last_error);
}
// set TCP_NODELAY
int enable_flag = 1;
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char *)&enable_flag, sizeof(enable_flag));
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void send(const char *data, size_t n_bytes)
{
size_t bytes_sent = 0;
while (bytes_sent < n_bytes)
{
const int send_flags = 0;
auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags);
if (write_result == SOCKET_ERROR)
{
int last_error = ::WSAGetLastError();
close();
throw_winsock_error_("send failed", last_error);
}
if (write_result == 0) // (probably should not happen but in any case..)
{
break;
}
bytes_sent += static_cast<size_t>(write_result);
}
}
};
} // namespace details
} // namespace spdlog

View File

@@ -0,0 +1,145 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifdef _WIN32
#error include tcp_client-windows.h instead
#endif
// tcp client helper
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <string>
namespace spdlog {
namespace details {
class tcp_client
{
int socket_ = -1;
public:
bool is_connected() const
{
return socket_ != -1;
}
void close()
{
if (is_connected())
{
::close(socket_);
socket_ = -1;
}
}
int fd() const
{
return socket_;
}
~tcp_client()
{
close();
}
// try to connect or throw on failure
void connect(const std::string &host, int port)
{
close();
struct addrinfo hints
{};
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
hints.ai_protocol = 0;
auto port_str = std::to_string(port);
struct addrinfo *addrinfo_result;
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
if (rv != 0)
{
auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv));
throw_spdlog_ex(msg);
}
// Try each address until we successfully connect(2).
int last_errno = 0;
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
{
int const flags = SOCK_CLOEXEC;
socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol);
if (socket_ == -1)
{
last_errno = errno;
continue;
}
rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen);
if (rv == 0)
{
break;
}
else
{
last_errno = errno;
::close(socket_);
socket_ = -1;
}
}
::freeaddrinfo(addrinfo_result);
if (socket_ == -1)
{
throw_spdlog_ex("::connect failed", last_errno);
}
// set TCP_NODELAY
int enable_flag = 1;
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, (char *)&enable_flag, sizeof(enable_flag));
// prevent sigpipe on systems where MSG_NOSIGNAL is not available
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, (char *)&enable_flag, sizeof(enable_flag));
#endif
#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
#error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
#endif
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void send(const char *data, size_t n_bytes)
{
size_t bytes_sent = 0;
while (bytes_sent < n_bytes)
{
#if defined(MSG_NOSIGNAL)
const int send_flags = MSG_NOSIGNAL;
#else
const int send_flags = 0;
#endif
auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags);
if (write_result < 0)
{
close();
throw_spdlog_ex("write(2) failed", errno);
}
if (write_result == 0) // (probably should not happen but in any case..)
{
break;
}
bytes_sent += static_cast<size_t>(write_result);
}
}
};
} // namespace details
} // namespace spdlog

View File

@@ -18,8 +18,8 @@ SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std
{
if (threads_n == 0 || threads_n > 1000)
{
SPDLOG_THROW(spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
"range is 1-1000)"));
throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
"range is 1-1000)");
}
for (size_t i = 0; i < threads_n; i++)
{
@@ -113,7 +113,7 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_()
}
default: {
assert(false && "Unexpected async_msg_type");
assert(false);
}
}

View File

@@ -79,7 +79,7 @@ struct async_msg : log_msg_buffer
{}
};
class thread_pool
class SPDLOG_API thread_pool
{
public:
using item_type = async_msg;

View File

@@ -0,0 +1,11 @@
#pragma once
#ifndef NOMINMAX
#define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>