mirror of
https://github.com/gabime/spdlog.git
synced 2026-04-10 11:34:29 +08:00
61
src/details/async_log_msg.cpp
Normal file
61
src/details/async_log_msg.cpp
Normal 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
|
||||
@@ -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
|
||||
40
src/details/err_helper.cpp
Normal file
40
src/details/err_helper.cpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user