Skip to content

Commit

Permalink
Merge branch 'gabime:v1.x' into v1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxwellGengYF authored Mar 24, 2024
2 parents 0374935 + ec661f9 commit a304837
Show file tree
Hide file tree
Showing 15 changed files with 311 additions and 29 deletions.
1 change: 0 additions & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ clang-analyzer-*,

WarningsAsErrors: ''
HeaderFilterRegex: '*spdlog/[^f].*'
AnalyzeTemporaryDtors: false
FormatStyle: none

CheckOptions:
Expand Down
23 changes: 13 additions & 10 deletions INSTALL
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
Header only version:
Header Only Version
==================================================================
Just copy the files to your build tree and use a C++11 compiler.
Just copy the files to your build tree and use a C++11 compiler.
Or use CMake:
```
add_executable(example_header_only example.cpp)
target_link_libraries(example_header_only spdlog::spdlog_header_only)
```


Compiled library version:
Compiled Library Version
==================================================================
CMake:
```
add_executable(example example.cpp)
target_link_libraries(example spdlog::spdlog)
```

Or copy files src/*.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler.

Tested on:
Important Information for Compilation:
==================================================================
* If you encounter compilation errors with gcc 4.8.x, please note that gcc 4.8.x does not fully support C++11. In such cases, consider upgrading your compiler or using a different version that fully supports C++11 standards

Tested on:
gcc 4.8.1 and above
clang 3.5
Visual Studio 2013




Visual Studio 2013
2 changes: 1 addition & 1 deletion bench/latency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) {
tracing_null_logger_st->enable_backtrace(64);
benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st);

#ifdef __linux
#ifdef __linux__
bench_dev_null();
#endif // __linux__

Expand Down
12 changes: 7 additions & 5 deletions include/spdlog/async_logger-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ SPDLOG_LOGGER_CATCH(msg.source)
}

// send flush request to the thread pool
SPDLOG_INLINE void spdlog::async_logger::flush_(){
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
}
else {
SPDLOG_INLINE void spdlog::async_logger::flush_(){SPDLOG_TRY{auto pool_ptr = thread_pool_.lock();
if (!pool_ptr) {
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
}

std::future<void> future = pool_ptr->post_flush(shared_from_this(), overflow_policy_);
// Wait for the flush operation to complete.
// This might throw exception if the flush message get dropped because of overflow.
future.get();
}
SPDLOG_LOGGER_CATCH(source_loc())
}
Expand Down
2 changes: 2 additions & 0 deletions include/spdlog/details/circular_q.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <cassert>
#include <vector>

#include "spdlog/common.h"

namespace spdlog {
namespace details {
template <typename T>
Expand Down
4 changes: 2 additions & 2 deletions include/spdlog/details/os-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT {

#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
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)()) / 2 - 1) {
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 4 - 1) {
throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
}

Expand All @@ -450,7 +450,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) {
}

int result_size = static_cast<int>(target.capacity());
if ((wstr_size + 1) * 2 > result_size) {
if ((wstr_size + 1) * 4 > result_size) {
result_size =
::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
}
Expand Down
17 changes: 13 additions & 4 deletions include/spdlog/details/registry-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,23 @@ SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_na
}

#if __cplusplus >= 201703L // C++17
// if the map is small do a sequential search and avoid creating string for find(logger_name)
// otherwise use the standard find()
SPDLOG_INLINE std::shared_ptr<logger> registry::get(std::string_view logger_name) {
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (const auto &[key, val] : loggers_) {
if (key == logger_name) {
return val;
if (loggers_.size() <= 10) {
for (const auto &[key, val]: loggers_) {
if (logger_name == key) {
return val;
}
}
return nullptr;
}
// otherwise use the normal map lookup
else {
auto found = loggers_.find(std::string(logger_name));
return found == loggers_.end() ? nullptr : found->second;
}
return nullptr;
}

SPDLOG_INLINE std::shared_ptr<logger> registry::get(const char *logger_name) {
Expand Down
11 changes: 8 additions & 3 deletions include/spdlog/details/thread_pool-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr,
post_async_msg_(std::move(async_m), overflow_policy);
}

void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr,
async_overflow_policy overflow_policy) {
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
std::future<void> SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr,
async_overflow_policy overflow_policy) {
std::promise<void> promise;
std::future<void> future = promise.get_future();
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush, std::move(promise)),
overflow_policy);
return future;
}

size_t SPDLOG_INLINE thread_pool::overrun_counter() { return q_.overrun_counter(); }
Expand Down Expand Up @@ -108,6 +112,7 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_() {
}
case async_msg_type::flush: {
incoming_async_msg.worker_ptr->backend_flush_();
incoming_async_msg.flush_promise.set_value();
return true;
}

Expand Down
19 changes: 16 additions & 3 deletions include/spdlog/details/thread_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <chrono>
#include <functional>
#include <future>
#include <memory>
#include <thread>
#include <vector>
Expand All @@ -27,6 +28,7 @@ enum class async_msg_type { log, flush, terminate };
struct async_msg : log_msg_buffer {
async_msg_type msg_type{async_msg_type::log};
async_logger_ptr worker_ptr;
std::promise<void> flush_promise;

async_msg() = default;
~async_msg() = default;
Expand Down Expand Up @@ -56,12 +58,22 @@ struct async_msg : log_msg_buffer {
async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m)
: log_msg_buffer{m},
msg_type{the_type},
worker_ptr{std::move(worker)} {}
worker_ptr{std::move(worker)},
flush_promise{} {}

async_msg(async_logger_ptr &&worker, async_msg_type the_type)
: log_msg_buffer{},
msg_type{the_type},
worker_ptr{std::move(worker)} {}
worker_ptr{std::move(worker)},
flush_promise{} {}

async_msg(async_logger_ptr &&worker,
async_msg_type the_type,
std::promise<void> &&promise)
: log_msg_buffer{},
msg_type{the_type},
worker_ptr{std::move(worker)},
flush_promise{std::move(promise)} {}

explicit async_msg(async_msg_type the_type)
: async_msg{nullptr, the_type} {}
Expand All @@ -88,7 +100,8 @@ class SPDLOG_API thread_pool {
void post_log(async_logger_ptr &&worker_ptr,
const details::log_msg &msg,
async_overflow_policy overflow_policy);
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy);
std::future<void> post_flush(async_logger_ptr &&worker_ptr,
async_overflow_policy overflow_policy);
size_t overrun_counter();
void reset_overrun_counter();
size_t discard_counter();
Expand Down
31 changes: 31 additions & 0 deletions include/spdlog/mdc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <spdlog/common.h>
#include <map>

namespace spdlog {

class SPDLOG_API mdc {
public:
static void put(const std::string &key, const std::string &value) {
get_context()[key] = value;
}

static std::string get(const std::string &key) {
auto &context = get_context();
auto it = context.find(key);
if (it != context.end()) {
return it->second;
}
return "";
}

static void remove(const std::string &key) { get_context().erase(key); }

static void clear() { get_context().clear(); }

static std::map<std::string, std::string> &get_context() {
static thread_local std::map<std::string, std::string> context;
return context;
}
};

} // namespace spdlog
42 changes: 42 additions & 0 deletions include/spdlog/pattern_formatter-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <spdlog/details/fmt_helper.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/mdc.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/formatter.h>

Expand Down Expand Up @@ -867,6 +868,43 @@ class full_formatter final : public flag_formatter {
memory_buf_t cached_datetime_;
};

// Class for formatting Mapped Diagnostic Context (MDC) in log messages.
// Example: [logger-name] [info] [mdc_key_1:mdc_value_1 mdc_key_2:mdc_value_2] some message
template <typename ScopedPadder>
class mdc_formatter : public flag_formatter {
public:
explicit mdc_formatter(padding_info padinfo)
: flag_formatter(padinfo) {}

void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override {
auto mdc_map = mdc::get_context();
if (mdc_map.empty()) {
ScopedPadder p(0, padinfo_, dest);
return;
} else {
auto last_element = --mdc_map.end();
for (auto it = mdc_map.begin(); it != mdc_map.end(); ++it) {
auto &pair = *it;
const auto &key = pair.first;
const auto &value = pair.second;
size_t content_size = key.size() + value.size() + 1; // 1 for ':'

if (it != last_element) {
content_size++; // 1 for ' '
}

ScopedPadder p(content_size, padinfo_, dest);
fmt_helper::append_string_view(key, dest);
fmt_helper::append_string_view(":", dest);
fmt_helper::append_string_view(value, dest);
if (it != last_element) {
fmt_helper::append_string_view(" ", dest);
}
}
}
}
};

} // namespace details

SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern,
Expand Down Expand Up @@ -1159,6 +1197,10 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i
padding));
break;

case ('&'):
formatters_.push_back(details::make_unique<details::mdc_formatter<Padder>>(padding));
break;

default: // Unknown flag appears as is
auto unknown_flag = details::make_unique<details::aggregate_formatter>();

Expand Down
4 changes: 4 additions & 0 deletions include/spdlog/stopwatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ class stopwatch {
return std::chrono::duration<double>(clock::now() - start_tp_);
}

std::chrono::milliseconds elapsed_ms() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start_tp_);
}

void reset() { start_tp_ = clock::now(); }
};
} // namespace spdlog
Expand Down
1 change: 1 addition & 0 deletions tests/includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/details/fmt_helper.h"
#include "spdlog/mdc.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/null_sink.h"
Expand Down
43 changes: 43 additions & 0 deletions tests/test_async.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,49 @@ TEST_CASE("flush", "[async]") {
REQUIRE(test_sink->flush_counter() == 1);
}

TEST_CASE("multithread flush", "[async]") {
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
size_t queue_size = 2;
size_t messages = 10;
size_t n_threads = 10;
size_t flush_count = 2048;
std::mutex mtx;
std::vector<std::string> errmsgs;
{
auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1);
auto logger = std::make_shared<spdlog::async_logger>(
"as", test_sink, tp, spdlog::async_overflow_policy::discard_new);

logger->set_error_handler([&](const std::string &) {
std::unique_lock<std::mutex> lock(mtx);
errmsgs.push_back("Broken promise");
});

for (size_t i = 0; i < messages; i++) {
logger->info("Hello message #{}", i);
}

std::vector<std::thread> threads;
for (size_t i = 0; i < n_threads; i++) {
threads.emplace_back([logger, flush_count] {
for (size_t j = 0; j < flush_count; j++) {
// flush does not throw exception even if failed.
// Instead, the error handler is invoked.
logger->flush();
}
});
}

for (auto &t : threads) {
t.join();
}
}
REQUIRE(test_sink->flush_counter() >= 1);
REQUIRE(test_sink->flush_counter() + errmsgs.size() == n_threads * flush_count);
REQUIRE(errmsgs.size() >= 1);
REQUIRE(errmsgs[0] == "Broken promise");
}

TEST_CASE("async periodic flush", "[async]") {
auto logger = spdlog::create_async<spdlog::sinks::test_sink_mt>("as");
auto test_sink = std::static_pointer_cast<spdlog::sinks::test_sink_mt>(logger->sinks()[0]);
Expand Down
Loading

0 comments on commit a304837

Please sign in to comment.