Asink sink (#3309)

Replace async logger with async sink
This commit is contained in:
Gabi Melman
2025-01-05 02:17:31 +02:00
committed by GitHub
parent 166843ff3a
commit 83c9ede9e6
82 changed files with 986 additions and 1789 deletions

View File

@@ -0,0 +1,61 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/async_log_msg.h"
namespace spdlog {
namespace details {
async_log_msg::async_log_msg(const type type)
: msg_type_{type} {}
// copy logger name and payload to buffer so can be used asynchronously
// note: source location pointers are copied without allocation since they
// are compiler generated const chars* (__FILE__, __LINE__, __FUNCTION__)
// if you pass custom strings to source location, make sure they outlive the async_log_msg
async_log_msg::async_log_msg(const type type, const log_msg &orig_msg)
: log_msg{orig_msg}, msg_type_(type) {
buffer_.append(logger_name);
buffer_.append(payload);
update_string_views();
}
async_log_msg::async_log_msg(const async_log_msg &other)
: log_msg{other}, msg_type_{other.msg_type_} {
buffer_.append(logger_name);
buffer_.append(payload);
update_string_views();
}
async_log_msg::async_log_msg(async_log_msg &&other) noexcept
: log_msg{other}, msg_type_{other.msg_type_}, buffer_{std::move(other.buffer_)} {
update_string_views();
}
async_log_msg &async_log_msg::operator=(const async_log_msg &other) {
if (this == &other) return *this;
log_msg::operator=(other);
msg_type_ = other.msg_type_;
buffer_.clear();
buffer_.append(other.buffer_.data(), other.buffer_.data() + other.buffer_.size());
update_string_views();
return *this;
}
async_log_msg &async_log_msg::operator=(async_log_msg &&other) noexcept {
if (this == &other) return *this;
log_msg::operator=(other);
msg_type_ = other.msg_type_;
buffer_ = std::move(other.buffer_);
update_string_views();
return *this;
}
void async_log_msg::update_string_views() {
logger_name = string_view_t{buffer_.data(), logger_name.size()};
payload = string_view_t{buffer_.data() + logger_name.size(), payload.size()};
}
} // namespace details
} // namespace spdlog

View File

@@ -1,49 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/context.h"
#include "spdlog/logger.h"
#ifndef SPDLOG_DISABLE_GLOBAL_LOGGER
#include "spdlog/sinks/stdout_color_sinks.h"
#endif // SPDLOG_DISABLE_GLOBAL_LOGGER
#include <memory>
namespace spdlog {
namespace details {
context::context(std::unique_ptr<logger> global_logger) { global_logger_ = std::move(global_logger); }
std::shared_ptr<logger> context::global_logger() { return global_logger_; }
// Return raw ptr to the global logger.
// To be used directly by the spdlog default api (e.g. spdlog::info)
// This make the default API faster, but cannot be used concurrently with set_global_logger().
// e.g do not call set_global_logger() from one thread while calling spdlog::info() from another.
logger *context::global_logger_raw() const noexcept { return global_logger_.get(); }
// set global logger
void context::set_logger(std::shared_ptr<logger> new_global_logger) { global_logger_ = std::move(new_global_logger); }
void context::set_tp(std::shared_ptr<thread_pool> tp) {
std::lock_guard lock(tp_mutex_);
tp_ = std::move(tp);
}
std::shared_ptr<thread_pool> context::get_tp() {
std::lock_guard lock(tp_mutex_);
return tp_;
}
// clean all resources and threads started by the registry
void context::shutdown() {
std::lock_guard lock(tp_mutex_);
tp_.reset();
}
std::recursive_mutex &context::tp_mutex() { return tp_mutex_; }
} // namespace details
} // namespace spdlog

View File

@@ -0,0 +1,40 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "iostream"
#include "spdlog/details/err_helper.h"
#include "spdlog/details/os.h"
namespace spdlog {
namespace details {
// Prints error to stderr with source location (if available). A stderr sink is not used because reaching
// this point might indicate a problem with the logging system itself so we use fputs() directly.
void err_helper::handle_ex(const std::string &origin, const source_loc &loc, const std::exception &ex) const {
if (custom_err_handler_) {
custom_err_handler_(ex.what());
return;
}
const auto tm_time = os::localtime();
char date_buf[32];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
std::string msg;
if (loc.empty()) {
msg = fmt_lib::format("[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, origin, ex.what());
} else {
msg = fmt_lib::format("[*** LOG ERROR ***] [{}({})] [{}] [{}] {}\n", loc.filename, loc.line, date_buf, origin,
ex.what());
}
std::fputs(msg.c_str(), stderr);
}
void err_helper::handle_unknown_ex(const std::string &origin, const source_loc &loc) const {
handle_ex(origin, loc, std::runtime_error("unknown exception"));
}
void err_helper::set_err_handler(err_handler handler) {
custom_err_handler_ = std::move(handler);
}
} // namespace details
} // namespace spdlog

View File

@@ -1,54 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/log_msg_buffer.h"
namespace spdlog {
namespace details {
// copy logger name and payload to buffer so can be used asynchronously
// note: source location pointers are copied without allocation since they
// are compiler generated const chars* (__FILE__, __LINE__, __FUNCTION__)
// if you pass custom strings to source location, make sure they outlive the log_msg_buffer
log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
: log_msg{orig_msg} {
buffer.append(logger_name);
buffer.append(payload);
update_string_views();
}
log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
: log_msg{other} {
buffer.append(logger_name);
buffer.append(payload);
update_string_views();
}
log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) noexcept
: log_msg{other},
buffer{std::move(other.buffer)} {
update_string_views();
}
log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) {
log_msg::operator=(other);
buffer.clear();
buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
update_string_views();
return *this;
}
log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) noexcept {
log_msg::operator=(other);
buffer = std::move(other.buffer);
update_string_views();
return *this;
}
void log_msg_buffer::update_string_views() {
logger_name = string_view_t{buffer.data(), logger_name.size()};
payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
}
} // namespace details
} // namespace spdlog

View File

@@ -1,117 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/thread_pool.h"
#include <cassert>
#include "spdlog/common.h"
namespace spdlog {
namespace details {
thread_pool::thread_pool(size_t q_max_items,
size_t threads_n,
std::function<void()> on_thread_start,
std::function<void()> on_thread_stop)
: q_(q_max_items) {
if (threads_n == 0 || threads_n > 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++) {
threads_.emplace_back([this, on_thread_start, on_thread_stop] {
on_thread_start();
this->thread_pool::worker_loop_();
on_thread_stop();
});
}
}
thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start)
: thread_pool(q_max_items, threads_n, on_thread_start, [] {}) {}
thread_pool::thread_pool(size_t q_max_items, size_t threads_n)
: thread_pool(q_max_items, threads_n, [] {}, [] {}) {}
// message all threads to terminate gracefully join them
thread_pool::~thread_pool() {
try {
for (size_t i = 0; i < threads_.size(); i++) {
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
}
for (auto &t : threads_) {
t.join();
}
} catch (...) {
}
}
void thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) {
async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg);
post_async_msg_(std::move(async_m), overflow_policy);
}
void 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);
}
size_t thread_pool::overrun_counter() { return q_.overrun_counter(); }
void thread_pool::reset_overrun_counter() { q_.reset_overrun_counter(); }
size_t thread_pool::discard_counter() { return q_.discard_counter(); }
void thread_pool::reset_discard_counter() { q_.reset_discard_counter(); }
size_t thread_pool::queue_size() { return q_.size(); }
void thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) {
if (overflow_policy == async_overflow_policy::block) {
q_.enqueue(std::move(new_msg));
} else if (overflow_policy == async_overflow_policy::overrun_oldest) {
q_.enqueue_nowait(std::move(new_msg));
} else {
assert(overflow_policy == async_overflow_policy::discard_new);
q_.enqueue_if_have_room(std::move(new_msg));
}
}
void thread_pool::worker_loop_() {
while (process_next_msg_()) {
}
}
// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool thread_pool::process_next_msg_() {
async_msg incoming_async_msg;
q_.dequeue(incoming_async_msg);
switch (incoming_async_msg.msg_type) {
case async_msg_type::log: {
incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
return true;
}
case async_msg_type::flush: {
incoming_async_msg.worker_ptr->backend_flush_();
return true;
}
case async_msg_type::terminate: {
return false;
}
default: {
assert(false);
}
}
return true;
}
} // namespace details
} // namespace spdlog