-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
df757a4
commit bc072c4
Showing
105 changed files
with
26,541 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||
// Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||
|
||
#pragma once | ||
|
||
// | ||
// Async logging using global thread pool | ||
// All loggers created here share same global thread pool. | ||
// Each log message is pushed to a queue along with a shared pointer to the | ||
// logger. | ||
// If a logger deleted while having pending messages in the queue, it's actual | ||
// destruction will defer | ||
// until all its messages are processed by the thread pool. | ||
// This is because each message in the queue holds a shared_ptr to the | ||
// originating logger. | ||
|
||
#include <spdlog/async_logger.h> | ||
#include <spdlog/details/registry.h> | ||
#include <spdlog/details/thread_pool.h> | ||
|
||
#include <memory> | ||
#include <mutex> | ||
#include <functional> | ||
|
||
namespace spdlog { | ||
|
||
namespace details { | ||
static const size_t default_async_q_size = 8192; | ||
} | ||
|
||
// async logger factory - creates async loggers backed with thread pool. | ||
// if a global thread pool doesn't already exist, create it with default queue | ||
// size of 8192 items and single thread. | ||
template<async_overflow_policy OverflowPolicy = async_overflow_policy::block> | ||
struct async_factory_impl | ||
{ | ||
template<typename Sink, typename... SinkArgs> | ||
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) | ||
{ | ||
auto ®istry_inst = details::registry::instance(); | ||
|
||
// create global thread pool if not already exists.. | ||
|
||
auto &mutex = registry_inst.tp_mutex(); | ||
std::lock_guard<std::recursive_mutex> tp_lock(mutex); | ||
auto tp = registry_inst.get_tp(); | ||
if (tp == nullptr) | ||
{ | ||
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U); | ||
registry_inst.set_tp(tp); | ||
} | ||
|
||
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); | ||
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); | ||
registry_inst.initialize_logger(new_logger); | ||
return new_logger; | ||
} | ||
}; | ||
|
||
using async_factory = async_factory_impl<async_overflow_policy::block>; | ||
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>; | ||
|
||
template<typename Sink, typename... SinkArgs> | ||
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&...sink_args) | ||
{ | ||
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); | ||
} | ||
|
||
template<typename Sink, typename... SinkArgs> | ||
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&...sink_args) | ||
{ | ||
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); | ||
} | ||
|
||
// set global thread pool. | ||
inline void init_thread_pool( | ||
size_t q_size, size_t thread_count, std::function<void()> on_thread_start, std::function<void()> on_thread_stop) | ||
{ | ||
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start, on_thread_stop); | ||
details::registry::instance().set_tp(std::move(tp)); | ||
} | ||
|
||
inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start) | ||
{ | ||
init_thread_pool(q_size, thread_count, on_thread_start, [] {}); | ||
} | ||
|
||
inline void init_thread_pool(size_t q_size, size_t thread_count) | ||
{ | ||
init_thread_pool( | ||
q_size, thread_count, [] {}, [] {}); | ||
} | ||
|
||
// get the global thread pool. | ||
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() | ||
{ | ||
return details::registry::instance().get_tp(); | ||
} | ||
} // namespace spdlog |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||
// Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||
|
||
#pragma once | ||
|
||
#ifndef SPDLOG_HEADER_ONLY | ||
# include <spdlog/async_logger.h> | ||
#endif | ||
|
||
#include <spdlog/sinks/sink.h> | ||
#include <spdlog/details/thread_pool.h> | ||
|
||
#include <memory> | ||
#include <string> | ||
|
||
SPDLOG_INLINE spdlog::async_logger::async_logger( | ||
std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) | ||
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) | ||
{} | ||
|
||
SPDLOG_INLINE spdlog::async_logger::async_logger( | ||
std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) | ||
: async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) | ||
{} | ||
|
||
// send the log message to the thread pool | ||
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ | ||
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); | ||
} | ||
else | ||
{ | ||
throw_spdlog_ex("async log: thread pool doesn't exist anymore"); | ||
} | ||
} | ||
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 | ||
{ | ||
throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); | ||
} | ||
} | ||
SPDLOG_LOGGER_CATCH(source_loc()) | ||
} | ||
|
||
// | ||
// backend functions - called from the thread pool to do the actual job | ||
// | ||
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) | ||
{ | ||
for (auto &sink : sinks_) | ||
{ | ||
if (sink->should_log(msg.level)) | ||
{ | ||
SPDLOG_TRY | ||
{ | ||
sink->log(msg); | ||
} | ||
SPDLOG_LOGGER_CATCH(msg.source) | ||
} | ||
} | ||
|
||
if (should_flush_(msg)) | ||
{ | ||
backend_flush_(); | ||
} | ||
} | ||
|
||
SPDLOG_INLINE void spdlog::async_logger::backend_flush_() | ||
{ | ||
for (auto &sink : sinks_) | ||
{ | ||
SPDLOG_TRY | ||
{ | ||
sink->flush(); | ||
} | ||
SPDLOG_LOGGER_CATCH(source_loc()) | ||
} | ||
} | ||
|
||
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) | ||
{ | ||
auto cloned = std::make_shared<spdlog::async_logger>(*this); | ||
cloned->name_ = std::move(new_name); | ||
return cloned; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||
// Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||
|
||
#pragma once | ||
|
||
// Fast asynchronous logger. | ||
// Uses pre allocated queue. | ||
// Creates a single back thread to pop messages from the queue and log them. | ||
// | ||
// Upon each log write the logger: | ||
// 1. Checks if its log level is enough to log the message | ||
// 2. Push a new copy of the message to a queue (or block the caller until | ||
// space is available in the queue) | ||
// Upon destruction, logs all remaining messages in the queue before | ||
// destructing.. | ||
|
||
#include <spdlog/logger.h> | ||
|
||
namespace spdlog { | ||
|
||
// Async overflow policy - block by default. | ||
enum class async_overflow_policy | ||
{ | ||
block, // Block until message can be enqueued | ||
overrun_oldest // Discard oldest message in the queue if full when trying to | ||
// add new item. | ||
}; | ||
|
||
namespace details { | ||
class thread_pool; | ||
} | ||
|
||
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>, public logger | ||
{ | ||
friend class details::thread_pool; | ||
|
||
public: | ||
template<typename It> | ||
async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, | ||
async_overflow_policy overflow_policy = async_overflow_policy::block) | ||
: logger(std::move(logger_name), begin, end) | ||
, thread_pool_(std::move(tp)) | ||
, overflow_policy_(overflow_policy) | ||
{} | ||
|
||
async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, | ||
async_overflow_policy overflow_policy = async_overflow_policy::block); | ||
|
||
async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, | ||
async_overflow_policy overflow_policy = async_overflow_policy::block); | ||
|
||
std::shared_ptr<logger> clone(std::string new_name) override; | ||
|
||
protected: | ||
void sink_it_(const details::log_msg &msg) override; | ||
void flush_() override; | ||
void backend_sink_it_(const details::log_msg &incoming_log_msg); | ||
void backend_flush_(); | ||
|
||
private: | ||
std::weak_ptr<details::thread_pool> thread_pool_; | ||
async_overflow_policy overflow_policy_; | ||
}; | ||
} // namespace spdlog | ||
|
||
#ifdef SPDLOG_HEADER_ONLY | ||
# include "async_logger-inl.h" | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||
// Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||
|
||
#pragma once | ||
#include <spdlog/cfg/helpers.h> | ||
#include <spdlog/details/registry.h> | ||
|
||
// | ||
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" | ||
// | ||
// set all loggers to debug level: | ||
// example.exe "SPDLOG_LEVEL=debug" | ||
|
||
// set logger1 to trace level | ||
// example.exe "SPDLOG_LEVEL=logger1=trace" | ||
|
||
// turn off all logging except for logger1 and logger2: | ||
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" | ||
|
||
namespace spdlog { | ||
namespace cfg { | ||
|
||
// search for SPDLOG_LEVEL= in the args and use it to init the levels | ||
inline void load_argv_levels(int argc, const char **argv) | ||
{ | ||
const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; | ||
for (int i = 1; i < argc; i++) | ||
{ | ||
std::string arg = argv[i]; | ||
if (arg.find(spdlog_level_prefix) == 0) | ||
{ | ||
auto levels_string = arg.substr(spdlog_level_prefix.size()); | ||
helpers::load_levels(levels_string); | ||
} | ||
} | ||
} | ||
|
||
inline void load_argv_levels(int argc, char **argv) | ||
{ | ||
load_argv_levels(argc, const_cast<const char **>(argv)); | ||
} | ||
|
||
} // namespace cfg | ||
} // namespace spdlog |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||
// Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||
|
||
#pragma once | ||
#include <spdlog/cfg/helpers.h> | ||
#include <spdlog/details/registry.h> | ||
#include <spdlog/details/os.h> | ||
|
||
// | ||
// Init levels and patterns from env variables SPDLOG_LEVEL | ||
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). | ||
// Note - fallback to "info" level on unrecognized levels | ||
// | ||
// Examples: | ||
// | ||
// set global level to debug: | ||
// export SPDLOG_LEVEL=debug | ||
// | ||
// turn off all logging except for logger1: | ||
// export SPDLOG_LEVEL="*=off,logger1=debug" | ||
// | ||
|
||
// turn off all logging except for logger1 and logger2: | ||
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info" | ||
|
||
namespace spdlog { | ||
namespace cfg { | ||
inline void load_env_levels() | ||
{ | ||
auto env_val = details::os::getenv("SPDLOG_LEVEL"); | ||
if (!env_val.empty()) | ||
{ | ||
helpers::load_levels(env_val); | ||
} | ||
} | ||
|
||
} // namespace cfg | ||
} // namespace spdlog |
Oops, something went wrong.