Skip to content

Commit 7fbb678

Browse files
committed
update
1 parent d79f0e7 commit 7fbb678

File tree

115 files changed

+26108
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+26108
-13
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2+
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3+
4+
#pragma once
5+
6+
//
7+
// Async logging using global thread pool
8+
// All loggers created here share same global thread pool.
9+
// Each log message is pushed to a queue along with a shared pointer to the
10+
// logger.
11+
// If a logger deleted while having pending messages in the queue, it's actual
12+
// destruction will defer
13+
// until all its messages are processed by the thread pool.
14+
// This is because each message in the queue holds a shared_ptr to the
15+
// originating logger.
16+
17+
#include <spdlog/async_logger.h>
18+
#include <spdlog/details/registry.h>
19+
#include <spdlog/details/thread_pool.h>
20+
21+
#include <functional>
22+
#include <memory>
23+
#include <mutex>
24+
25+
namespace spdlog {
26+
27+
namespace details {
28+
static const size_t default_async_q_size = 8192;
29+
}
30+
31+
// async logger factory - creates async loggers backed with thread pool.
32+
// if a global thread pool doesn't already exist, create it with default queue
33+
// size of 8192 items and single thread.
34+
template <async_overflow_policy OverflowPolicy = async_overflow_policy::block>
35+
struct async_factory_impl {
36+
template <typename Sink, typename... SinkArgs>
37+
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) {
38+
auto &registry_inst = details::registry::instance();
39+
40+
// create global thread pool if not already exists..
41+
42+
auto &mutex = registry_inst.tp_mutex();
43+
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
44+
auto tp = registry_inst.get_tp();
45+
if (tp == nullptr) {
46+
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
47+
registry_inst.set_tp(tp);
48+
}
49+
50+
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
51+
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink),
52+
std::move(tp), OverflowPolicy);
53+
registry_inst.initialize_logger(new_logger);
54+
return new_logger;
55+
}
56+
};
57+
58+
using async_factory = async_factory_impl<async_overflow_policy::block>;
59+
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
60+
61+
template <typename Sink, typename... SinkArgs>
62+
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name,
63+
SinkArgs &&...sink_args) {
64+
return async_factory::create<Sink>(std::move(logger_name),
65+
std::forward<SinkArgs>(sink_args)...);
66+
}
67+
68+
template <typename Sink, typename... SinkArgs>
69+
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name,
70+
SinkArgs &&...sink_args) {
71+
return async_factory_nonblock::create<Sink>(std::move(logger_name),
72+
std::forward<SinkArgs>(sink_args)...);
73+
}
74+
75+
// set global thread pool.
76+
inline void init_thread_pool(size_t q_size,
77+
size_t thread_count,
78+
std::function<void()> on_thread_start,
79+
std::function<void()> on_thread_stop) {
80+
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start,
81+
on_thread_stop);
82+
details::registry::instance().set_tp(std::move(tp));
83+
}
84+
85+
inline void init_thread_pool(size_t q_size,
86+
size_t thread_count,
87+
std::function<void()> on_thread_start) {
88+
init_thread_pool(q_size, thread_count, on_thread_start, [] {});
89+
}
90+
91+
inline void init_thread_pool(size_t q_size, size_t thread_count) {
92+
init_thread_pool(
93+
q_size, thread_count, [] {}, [] {});
94+
}
95+
96+
// get the global thread pool.
97+
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() {
98+
return details::registry::instance().get_tp();
99+
}
100+
} // namespace spdlog
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2+
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3+
4+
#pragma once
5+
6+
#ifndef SPDLOG_HEADER_ONLY
7+
#include <spdlog/async_logger.h>
8+
#endif
9+
10+
#include <spdlog/details/thread_pool.h>
11+
#include <spdlog/sinks/sink.h>
12+
13+
#include <memory>
14+
#include <string>
15+
16+
SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
17+
sinks_init_list sinks_list,
18+
std::weak_ptr<details::thread_pool> tp,
19+
async_overflow_policy overflow_policy)
20+
: async_logger(std::move(logger_name),
21+
sinks_list.begin(),
22+
sinks_list.end(),
23+
std::move(tp),
24+
overflow_policy) {}
25+
26+
SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
27+
sink_ptr single_sink,
28+
std::weak_ptr<details::thread_pool> tp,
29+
async_overflow_policy overflow_policy)
30+
: async_logger(
31+
std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {}
32+
33+
// send the log message to the thread pool
34+
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){
35+
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
36+
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
37+
}
38+
else {
39+
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
40+
}
41+
}
42+
SPDLOG_LOGGER_CATCH(msg.source)
43+
}
44+
45+
// send flush request to the thread pool
46+
SPDLOG_INLINE void spdlog::async_logger::flush_(){
47+
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
48+
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
49+
}
50+
else {
51+
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
52+
}
53+
}
54+
SPDLOG_LOGGER_CATCH(source_loc())
55+
}
56+
57+
//
58+
// backend functions - called from the thread pool to do the actual job
59+
//
60+
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) {
61+
for (auto &sink : sinks_) {
62+
if (sink->should_log(msg.level)) {
63+
SPDLOG_TRY { sink->log(msg); }
64+
SPDLOG_LOGGER_CATCH(msg.source)
65+
}
66+
}
67+
68+
if (should_flush_(msg)) {
69+
backend_flush_();
70+
}
71+
}
72+
73+
SPDLOG_INLINE void spdlog::async_logger::backend_flush_() {
74+
for (auto &sink : sinks_) {
75+
SPDLOG_TRY { sink->flush(); }
76+
SPDLOG_LOGGER_CATCH(source_loc())
77+
}
78+
}
79+
80+
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) {
81+
auto cloned = std::make_shared<spdlog::async_logger>(*this);
82+
cloned->name_ = std::move(new_name);
83+
return cloned;
84+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2+
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3+
4+
#pragma once
5+
6+
// Fast asynchronous logger.
7+
// Uses pre allocated queue.
8+
// Creates a single back thread to pop messages from the queue and log them.
9+
//
10+
// Upon each log write the logger:
11+
// 1. Checks if its log level is enough to log the message
12+
// 2. Push a new copy of the message to a queue (or block the caller until
13+
// space is available in the queue)
14+
// Upon destruction, logs all remaining messages in the queue before
15+
// destructing..
16+
17+
#include <spdlog/logger.h>
18+
19+
namespace spdlog {
20+
21+
// Async overflow policy - block by default.
22+
enum class async_overflow_policy {
23+
block, // Block until message can be enqueued
24+
overrun_oldest, // Discard oldest message in the queue if full when trying to
25+
// add new item.
26+
discard_new // Discard new message if the queue is full when trying to add new item.
27+
};
28+
29+
namespace details {
30+
class thread_pool;
31+
}
32+
33+
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>,
34+
public logger {
35+
friend class details::thread_pool;
36+
37+
public:
38+
template <typename It>
39+
async_logger(std::string logger_name,
40+
It begin,
41+
It end,
42+
std::weak_ptr<details::thread_pool> tp,
43+
async_overflow_policy overflow_policy = async_overflow_policy::block)
44+
: logger(std::move(logger_name), begin, end),
45+
thread_pool_(std::move(tp)),
46+
overflow_policy_(overflow_policy) {}
47+
48+
async_logger(std::string logger_name,
49+
sinks_init_list sinks_list,
50+
std::weak_ptr<details::thread_pool> tp,
51+
async_overflow_policy overflow_policy = async_overflow_policy::block);
52+
53+
async_logger(std::string logger_name,
54+
sink_ptr single_sink,
55+
std::weak_ptr<details::thread_pool> tp,
56+
async_overflow_policy overflow_policy = async_overflow_policy::block);
57+
58+
std::shared_ptr<logger> clone(std::string new_name) override;
59+
60+
protected:
61+
void sink_it_(const details::log_msg &msg) override;
62+
void flush_() override;
63+
void backend_sink_it_(const details::log_msg &incoming_log_msg);
64+
void backend_flush_();
65+
66+
private:
67+
std::weak_ptr<details::thread_pool> thread_pool_;
68+
async_overflow_policy overflow_policy_;
69+
};
70+
} // namespace spdlog
71+
72+
#ifdef SPDLOG_HEADER_ONLY
73+
#include "async_logger-inl.h"
74+
#endif
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2+
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3+
4+
#pragma once
5+
#include <spdlog/cfg/helpers.h>
6+
#include <spdlog/details/registry.h>
7+
8+
//
9+
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
10+
//
11+
// set all loggers to debug level:
12+
// example.exe "SPDLOG_LEVEL=debug"
13+
14+
// set logger1 to trace level
15+
// example.exe "SPDLOG_LEVEL=logger1=trace"
16+
17+
// turn off all logging except for logger1 and logger2:
18+
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
19+
20+
namespace spdlog {
21+
namespace cfg {
22+
23+
// search for SPDLOG_LEVEL= in the args and use it to init the levels
24+
inline void load_argv_levels(int argc, const char **argv) {
25+
const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
26+
for (int i = 1; i < argc; i++) {
27+
std::string arg = argv[i];
28+
if (arg.find(spdlog_level_prefix) == 0) {
29+
auto levels_string = arg.substr(spdlog_level_prefix.size());
30+
helpers::load_levels(levels_string);
31+
}
32+
}
33+
}
34+
35+
inline void load_argv_levels(int argc, char **argv) {
36+
load_argv_levels(argc, const_cast<const char **>(argv));
37+
}
38+
39+
} // namespace cfg
40+
} // namespace spdlog
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2+
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3+
4+
#pragma once
5+
#include <spdlog/cfg/helpers.h>
6+
#include <spdlog/details/os.h>
7+
#include <spdlog/details/registry.h>
8+
9+
//
10+
// Init levels and patterns from env variables SPDLOG_LEVEL
11+
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
12+
// Note - fallback to "info" level on unrecognized levels
13+
//
14+
// Examples:
15+
//
16+
// set global level to debug:
17+
// export SPDLOG_LEVEL=debug
18+
//
19+
// turn off all logging except for logger1:
20+
// export SPDLOG_LEVEL="*=off,logger1=debug"
21+
//
22+
23+
// turn off all logging except for logger1 and logger2:
24+
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
25+
26+
namespace spdlog {
27+
namespace cfg {
28+
inline void load_env_levels() {
29+
auto env_val = details::os::getenv("SPDLOG_LEVEL");
30+
if (!env_val.empty()) {
31+
helpers::load_levels(env_val);
32+
}
33+
}
34+
35+
} // namespace cfg
36+
} // namespace spdlog

0 commit comments

Comments
 (0)