1
0
mirror of https://github.com/gabime/spdlog.git synced 2025-01-16 01:37:58 +00:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Gabi Melman
208eb0ca07
Merge pull request #1473 from avrahamshukron/patch-1
README: add conda as a supported package manager
2020-03-15 22:07:39 +02:00
Avraham Shukron
f0403fa9e4
README: add conda as a supported package manager
spdlog is available on conda-forge for a long time.
https://anaconda.org/conda-forge/spdlog
2020-03-15 21:59:34 +02:00
gabime
3f86b250e6 Updated comment 2020-03-15 18:56:38 +02:00
gabime
d1819f5f76 clang-format 2020-03-15 18:51:52 +02:00
gabime
19c7e63858 Added final keywords to pattern_formatter classes 2020-03-15 18:46:10 +02:00
gabime
7efdcc26fe CMakeLists.txt: use same policy as fmt 2020-03-15 18:41:34 +02:00
gabime
3ab3970dd2 CMakeLists.txt: use same policy as fmt 2020-03-15 18:40:42 +02:00
gabime
5ab487dbae Updated example 2020-03-15 17:38:15 +02:00
gabime
55fbc2c78e Merge branch 'ngugcx-hexdump' into v1.x 2020-03-15 17:32:11 +02:00
gabime
643426e2b2 Small refactor 2020-03-15 17:20:02 +02:00
gabime
f31a834613 clang-format 2020-03-15 17:16:28 +02:00
gabime
683080be53 Fix clang-tidy warning 2020-03-15 17:14:52 +02:00
gabime
d14b8a9ad6 Merge branch 'hexdump' of https://github.com/ngugcx/spdlog into ngugcx-hexdump 2020-03-15 16:27:58 +02:00
ngugcx
0f87ba6c93 fix a test case error. 2020-03-15 20:21:58 +08:00
ngugcx
02bfa0898c Do not fill blanks to align if there is only one line. 2020-03-15 20:09:28 +08:00
ngugcx
f5313f92f1 Enhance to_hex like the unix command hexdump. 2020-03-15 12:01:31 +08:00
11 changed files with 169 additions and 67 deletions

View File

@ -3,6 +3,12 @@
cmake_minimum_required(VERSION 3.2)
if(${CMAKE_VERSION} VERSION_LESS 3.11)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.11)
endif()
ENABLE_LANGUAGE(C)
#---------------------------------------------------------------------------------------

View File

@ -32,6 +32,7 @@ $ cmake .. && make -j
* Arch Linux: `yaourt -S spdlog-git`
* vcpkg: `vcpkg install spdlog`
* conan: `spdlog/[>=1.4.1]`
* conda: `conda install -c conda-forge spdlog`
## Features

View File

@ -20,7 +20,7 @@ void err_handler_example();
void syslog_example();
#include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // for loading levels from the environment variables
#include "spdlog/cfg/env.h" // for loading levels from the environment variable
int main(int, char *[])
{
@ -172,6 +172,8 @@ void binary_example()
// logger->info("uppercase: {:X}", spdlog::to_hex(buf));
// logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
// logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
// logger->info("hexdump style: {:a}", spdlog::to_hex(buf));
// logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20));
}
// Compile time log levels.

View File

@ -17,16 +17,16 @@
#ifdef SPDLOG_COMPILED_LIB
#undef SPDLOG_HEADER_ONLY
# if defined(_WIN32) && defined(SPDLOG_SHARED_LIB)
# ifdef spdlog_EXPORTS
# define SPDLOG_API __declspec(dllexport)
# else
# define SPDLOG_API __declspec(dllimport)
# endif
# else
# define SPDLOG_API
# endif
# define SPDLOG_INLINE
#if defined(_WIN32) && defined(SPDLOG_SHARED_LIB)
#ifdef spdlog_EXPORTS
#define SPDLOG_API __declspec(dllexport)
#else
#define SPDLOG_API __declspec(dllimport)
#endif
#else
#define SPDLOG_API
#endif
#define SPDLOG_INLINE
#else
#define SPDLOG_API
#define SPDLOG_HEADER_ONLY

View File

@ -90,7 +90,7 @@ struct null_scoped_padder
};
template<typename ScopedPadder>
class name_formatter : public flag_formatter
class name_formatter final : public flag_formatter
{
public:
explicit name_formatter(padding_info padinfo)
@ -106,7 +106,7 @@ public:
// log level appender
template<typename ScopedPadder>
class level_formatter : public flag_formatter
class level_formatter final : public flag_formatter
{
public:
explicit level_formatter(padding_info padinfo)
@ -123,7 +123,7 @@ public:
// short log level appender
template<typename ScopedPadder>
class short_level_formatter : public flag_formatter
class short_level_formatter final : public flag_formatter
{
public:
explicit short_level_formatter(padding_info padinfo)
@ -156,7 +156,7 @@ static int to12h(const tm &t)
static std::array<const char *, 7> days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}};
template<typename ScopedPadder>
class a_formatter : public flag_formatter
class a_formatter final : public flag_formatter
{
public:
explicit a_formatter(padding_info padinfo)
@ -194,7 +194,7 @@ public:
static const std::array<const char *, 12> months{{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}};
template<typename ScopedPadder>
class b_formatter : public flag_formatter
class b_formatter final : public flag_formatter
{
public:
explicit b_formatter(padding_info padinfo)
@ -214,7 +214,7 @@ static const std::array<const char *, 12> full_months{
{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}};
template<typename ScopedPadder>
class B_formatter : public flag_formatter
class B_formatter final : public flag_formatter
{
public:
explicit B_formatter(padding_info padinfo)

View File

@ -187,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_);
auto clbk = [this](){this->flush_all();};
auto clbk = [this]() { this->flush_all(); };
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
}

View File

@ -49,14 +49,11 @@ class tcp_client
}
}
static void throw_winsock_error_(const std::string& msg, int last_error)
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);
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
SPDLOG_THROW(spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf)));
}
@ -111,20 +108,20 @@ public:
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();
last_error = ::WSAGetLastError();
WSACleanup();
continue;
}
@ -141,7 +138,7 @@ public:
::freeaddrinfo(addrinfo_result);
if (socket_ == INVALID_SOCKET)
{
WSACleanup();
WSACleanup();
throw_winsock_error_("connect failed", last_error);
}
@ -160,7 +157,7 @@ public:
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);

View File

@ -5,6 +5,8 @@
#pragma once
#include <cctype>
//
// Support for logging binary data as hex
// format flags:
@ -12,6 +14,7 @@
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.
// {:a} - show ASCII if :n is not set
//
// Examples:
@ -20,17 +23,19 @@
// logger->info("Some buffer {}", spdlog::to_hex(v));
// char buf[128];
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
namespace spdlog {
namespace details {
template<typename It>
class bytes_range
class dump_info
{
public:
bytes_range(It range_begin, It range_end)
dump_info(It range_begin, It range_end, size_t size_per_line)
: begin_(range_begin)
, end_(range_end)
, size_per_line_(size_per_line)
{}
It begin() const
@ -41,26 +46,31 @@ public:
{
return end_;
}
size_t size_per_line() const
{
return size_per_line_;
}
private:
It begin_, end_;
size_t size_per_line_;
};
} // namespace details
// create a bytes_range that wraps the given container
// create a dump_info that wraps the given container
template<typename Container>
inline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container)
inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container, size_t size_per_line = 32)
{
static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
using Iter = typename Container::const_iterator;
return details::bytes_range<Iter>(std::begin(container), std::end(container));
return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
}
// create bytes_range from ranges
// create dump_info from ranges
template<typename It>
inline details::bytes_range<It> to_hex(const It range_begin, const It range_end)
inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32)
{
return details::bytes_range<It>(range_begin, range_end);
return details::dump_info<It>(range_begin, range_end, size_per_line);
}
} // namespace spdlog
@ -68,15 +78,14 @@ inline details::bytes_range<It> to_hex(const It range_begin, const It range_end)
namespace fmt {
template<typename T>
struct formatter<spdlog::details::bytes_range<T>>
struct formatter<spdlog::details::dump_info<T>>
{
const std::size_t line_size = 100;
const char delimiter = ' ';
bool put_newlines = true;
bool put_delimiters = true;
bool use_uppercase = false;
bool put_positions = true; // position on start of each line
bool show_ascii = false;
// parse the format string flags
template<typename ParseContext>
@ -98,6 +107,13 @@ struct formatter<spdlog::details::bytes_range<T>>
break;
case 'n':
put_newlines = false;
show_ascii = false;
break;
case 'a':
if (put_newlines)
{
show_ascii = true;
}
break;
}
@ -108,53 +124,83 @@ struct formatter<spdlog::details::bytes_range<T>>
// format the given bytes range as hex
template<typename FormatContext, typename Container>
auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
{
SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
std::size_t pos = 0;
std::size_t column = line_size;
#if FMT_VERSION < 60000
auto inserter = ctx.begin();
#else
auto inserter = ctx.out();
#endif
for (auto &item : the_range)
int size_per_line = static_cast<int>(the_range.size_per_line());
auto start_of_line = the_range.begin();
for (auto i = the_range.begin(); i != the_range.end(); i++)
{
auto ch = static_cast<unsigned char>(item);
pos++;
auto ch = static_cast<unsigned char>(*i);
if (put_newlines && column >= line_size)
if (put_newlines && (i == the_range.begin() || i - start_of_line >= size_per_line))
{
column = put_newline(inserter, pos);
if (show_ascii && i != the_range.begin())
{
*inserter++ = delimiter;
*inserter++ = delimiter;
for (auto j = start_of_line; j < i; j++)
{
auto pc = static_cast<unsigned char>(*j);
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
}
}
put_newline(inserter, static_cast<size_t>(i - the_range.begin()));
// put first byte without delimiter in front of it
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f];
column += 2;
start_of_line = i;
continue;
}
if (put_delimiters)
{
*inserter++ = delimiter;
++column;
}
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f];
column += 2;
}
if (show_ascii) // add ascii to last line
{
if (the_range.end() - the_range.begin() > size_per_line)
{
auto blank_num = size_per_line - (the_range.end() - start_of_line);
while (blank_num-- > 0)
{
*inserter++ = delimiter;
*inserter++ = delimiter;
if (put_delimiters)
{
*inserter++ = delimiter;
}
}
}
*inserter++ = delimiter;
*inserter++ = delimiter;
for (auto j = start_of_line; j != the_range.end(); j++)
{
auto pc = static_cast<unsigned char>(*j);
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
}
}
return inserter;
}
// put newline(and position header)
// return the next column
template<typename It>
std::size_t put_newline(It inserter, std::size_t pos)
void put_newline(It inserter, std::size_t pos)
{
#ifdef _WIN32
*inserter++ = '\r';
@ -163,12 +209,7 @@ struct formatter<spdlog::details::bytes_range<T>>
if (put_positions)
{
fmt::format_to(inserter, "{:<04X}: ", pos - 1);
return 7;
}
else
{
return 1;
fmt::format_to(inserter, "{:<04X}: ", pos);
}
}
};

View File

@ -31,7 +31,7 @@ struct tcp_sink_config
{
std::string server_host;
int server_port;
bool lazy_connect = false; // if true connect on first log call instead of on construction
bool lazy_connect = false; // if true connect on first log call instead of on construction
tcp_sink_config(std::string host, int port)
: server_host{std::move(host)}
@ -46,14 +46,14 @@ public:
// connect to tcp host/port or throw if failed
// host can be hostname or ip address
explicit tcp_sink(tcp_sink_config sink_config):
config_{std::move(sink_config)}
explicit tcp_sink(tcp_sink_config sink_config)
: config_{std::move(sink_config)}
{
if (!config_.lazy_connect)
{
this->client_.connect(config_.server_host, config_.server_port);
}
}
}
~tcp_sink() override = default;

View File

@ -41,7 +41,11 @@ template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdl
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::synchronous_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt<spdlog::async_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stdout_color_st<spdlog::async_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt<spdlog::async_factory>(
const std::string &logger_name, color_mode mode);
template SPDLOG_API std::shared_ptr<spdlog::logger> spdlog::stderr_color_st<spdlog::async_factory>(
const std::string &logger_name, color_mode mode);

View File

@ -182,6 +182,57 @@ TEST_CASE("to_hex_no_delimiter", "[to_hex]")
REQUIRE(ends_with(output, "0000: 090A0B0CFFFF" + std::string(spdlog::details::os::default_eol)));
}
TEST_CASE("to_hex_show_ascii", "[to_hex]")
{
std::ostringstream oss;
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
spdlog::logger oss_logger("oss", oss_sink);
std::vector<unsigned char> v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff};
oss_logger.info("{:Xsa}", spdlog::to_hex(v, 8));
REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF ...A.K.." + std::string(spdlog::details::os::default_eol)));
}
TEST_CASE("to_hex_different_size_per_line", "[to_hex]")
{
std::ostringstream oss;
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
spdlog::logger oss_logger("oss", oss_sink);
std::vector<unsigned char> v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff};
oss_logger.info("{:Xsa}", spdlog::to_hex(v, 10));
REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF ...A.K.." + std::string(spdlog::details::os::default_eol)));
oss_logger.info("{:Xs}", spdlog::to_hex(v, 10));
REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol)));
oss_logger.info("{:Xsa}", spdlog::to_hex(v, 6));
REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B ...A.K" + std::string(spdlog::details::os::default_eol) + "0006: FFFF .." +
std::string(spdlog::details::os::default_eol)));
oss_logger.info("{:Xs}", spdlog::to_hex(v, 6));
REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B" + std::string(spdlog::details::os::default_eol) + "0006: FFFF" +
std::string(spdlog::details::os::default_eol)));
}
TEST_CASE("to_hex_no_ascii", "[to_hex]")
{
std::ostringstream oss;
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(oss);
spdlog::logger oss_logger("oss", oss_sink);
std::vector<unsigned char> v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff};
oss_logger.info("{:Xs}", spdlog::to_hex(v, 8));
REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol)));
oss_logger.info("{:Xsna}", spdlog::to_hex(v, 8));
REQUIRE(ends_with(oss.str(), "090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol)));
}
TEST_CASE("default logger API", "[default logger]")
{
std::ostringstream oss;