Commit 6f4cd8d3 authored by gabime's avatar gabime

thread_pool and refactoring async

parent 5e08950e
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
// //
// bench.cpp : spdlog benchmarks // bench.cpp : spdlog benchmarks
// //
#include "spdlog/async_logger.h" #include "spdlog/async.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/null_sink.h" #include "spdlog/sinks/null_sink.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include "utils.h" #include "utils.h"
#include <atomic> #include <atomic>
#include <cstdlib> // EXIT_FAILURE #include <cstdlib> // EXIT_FAILURE
...@@ -71,11 +71,10 @@ int main(int argc, char *argv[]) ...@@ -71,11 +71,10 @@ int main(int argc, char *argv[])
cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations " << endl; cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations " << endl;
cout << "*******************************************************************************\n"; cout << "*******************************************************************************\n";
spdlog::set_async_mode(queue_size);
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
{ {
auto as = spdlog::daily_logger_st("as", "logs/daily_async.log"); spdlog::init_thread_pool(queue_size, 1);
auto as = spdlog::daily_logger_mt<spdlog::create_async>("as", "logs/daily_async.log");
bench_mt(howmany, as, threads); bench_mt(howmany, as, threads);
spdlog::drop("as"); spdlog::drop("as");
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define SPDLOG_TRACE_ON #define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON #define SPDLOG_DEBUG_ON
#include "spdlog/async.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <iostream> #include <iostream>
...@@ -27,9 +28,10 @@ int main(int, char *[]) ...@@ -27,9 +28,10 @@ int main(int, char *[])
try try
{ {
// Console logger with color // Console logger with color
auto console = spd::stdout_color_mt("console"); auto console = spdlog::console<spd::stdout_color_mt>("console");
auto console2 = spdlog::console<spd::stdout_color_mt>("console");
console->info("Welcome to spdlog!"); console->info("Welcome to spdlog!");
console->error("Some error message with arg{}..", 1); console->error("Some error message with arg: {}", 1);
// Formatting examples // Formatting examples
console->warn("Easy padding in numbers like {:08d}", 12); console->warn("Easy padding in numbers like {:08d}", 12);
...@@ -105,13 +107,16 @@ int main(int, char *[]) ...@@ -105,13 +107,16 @@ int main(int, char *[])
void async_example() void async_example()
{ {
size_t q_size = 4096; // queue size must be power of 2
spdlog::set_async_mode(q_size); auto async_file = spd::basic_logger_mt<spdlog::create_async>("async_file_logger", "logs/async_log.txt");
auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
for (int i = 0; i < 100; ++i) for (int i = 0; i < 100; ++i)
{ {
async_file->info("Async message #{}", i); async_file->info("Async message #{}", i);
} }
// optional change thread pool settings *before* creating the logger:
// spdlog::init_thread_pool(8192, 1);
// if not called a defaults are: 8192 queue size and 1 worker thread.
} }
// syslog example (linux/osx/freebsd) // syslog example (linux/osx/freebsd)
......
...@@ -20,52 +20,39 @@ ...@@ -20,52 +20,39 @@
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <iostream>
#include <memory> #include <memory>
#include <string> #include <string>
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class async_log_helper; class thread_pool;
} }
class async_logger SPDLOG_FINAL : public logger class async_logger SPDLOG_FINAL : public std::enable_shared_from_this<async_logger>, public logger
{ {
friend class details::thread_pool;
public: public:
template<class It> template<class It>
async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size, async_logger(const std::string &logger_name, const It &begin, const It &end, std::weak_ptr<details::thread_pool> tp,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, async_overflow_policy overflow_policy = async_overflow_policy::block_retry);
const std::function<void()> &worker_warmup_cb = nullptr,
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
const std::function<void()> &worker_teardown_cb = nullptr);
async_logger(const std::string &logger_name, sinks_init_list sinks, size_t queue_size, async_logger(const std::string &logger_name, sinks_init_list sinks, std::weak_ptr<details::thread_pool> tp,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, async_overflow_policy overflow_policy = async_overflow_policy::block_retry);
const std::function<void()> &worker_warmup_cb = nullptr,
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
const std::function<void()> &worker_teardown_cb = nullptr);
async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size, async_logger(const std::string &logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, async_overflow_policy overflow_policy = async_overflow_policy::block_retry);
const std::function<void()> &worker_warmup_cb = nullptr,
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
const std::function<void()> &worker_teardown_cb = nullptr);
// Wait for the queue to be empty, and flush synchronously
// Warning: this can potentially last forever as we wait it to complete
void flush() override;
// Error handler
void set_error_handler(log_err_handler) override;
log_err_handler error_handler() override;
protected: protected:
void _sink_it(details::log_msg &msg) override; void _sink_it(details::log_msg &msg) override;
void _set_formatter(spdlog::formatter_ptr msg_formatter) override; void _flush() override;
void _set_pattern(const std::string &pattern, pattern_time_type pattern_time) override;
void _backend_log(details::log_msg &incoming_log_msg);
void _backend_flush();
private: private:
std::unique_ptr<details::async_log_helper> _async_log_helper; std::weak_ptr<details::thread_pool> _thread_pool;
async_overflow_policy _overflow_policy;
}; };
} // namespace spdlog } // namespace spdlog
......
Please put here your contribs. Popular contribs will be moved to main tree after stablization
...@@ -72,8 +72,7 @@ class async_log_helper ...@@ -72,8 +72,7 @@ class async_log_helper
msg_id(other.msg_id) msg_id(other.msg_id)
{ {
} }
dsdfsfs async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT
async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT
{ {
logger_name = std::move(other.logger_name); logger_name = std::move(other.logger_name);
level = other.level; level = other.level;
......
...@@ -5,82 +5,110 @@ ...@@ -5,82 +5,110 @@
#pragma once #pragma once
// Async Logger implementation // async logger implementation
// Use an async_sink (queue per logger) to perform the logging in a worker thread // uses a thread pool to perform the actual logging
#include "../async_logger.h" #include "../details/thread_pool.h"
#include "../details/async_log_helper.h"
#include <chrono> #include <chrono>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
template<class It> template<class It>
inline spdlog::async_logger::async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size, inline spdlog::async_logger::async_logger(const std::string &logger_name, const It &begin, const It &end,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
: logger(logger_name, begin, end) : logger(logger_name, begin, end)
, _async_log_helper(new details::async_log_helper( , _thread_pool(tp)
_formatter, _sinks, queue_size, _err_handler, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)) , _overflow_policy(overflow_policy)
{ {
} }
inline spdlog::async_logger::async_logger(const std::string &logger_name, sinks_init_list sinks_list, size_t queue_size, inline spdlog::async_logger::async_logger(const std::string &logger_name, sinks_init_list sinks_list,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb) : async_logger(logger_name, sinks_list.begin(), sinks_list.end(), tp, overflow_policy)
: async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms,
worker_teardown_cb)
{ {
} }
inline spdlog::async_logger::async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size, inline spdlog::async_logger::async_logger(
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb, const std::string &logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb) : async_logger(logger_name, {single_sink}, tp, overflow_policy)
: async_logger(
logger_name, {std::move(single_sink)}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)
{ {
} }
inline void spdlog::async_logger::flush() // send the log message to the thread pool
{ inline void spdlog::async_logger::_sink_it(details::log_msg &msg)
_async_log_helper->flush(true);
}
// Error handler
inline void spdlog::async_logger::set_error_handler(spdlog::log_err_handler err_handler)
{
_err_handler = err_handler;
_async_log_helper->set_error_handler(err_handler);
}
inline spdlog::log_err_handler spdlog::async_logger::error_handler()
{ {
return _err_handler; try
{
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
_incr_msg_counter(msg);
#endif
if (auto pool_ptr = _thread_pool.lock())
{
pool_ptr->post_log(shared_from_this(), std::move(msg), _overflow_policy);
}
else
{
throw spdlog_ex("async log: thread pool doens't exist anymore");
}
}
catch (const std::exception &ex)
{
_err_handler(ex.what());
}
catch (...)
{
_err_handler("Unknown exception in async logger " + _name);
}
} }
inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) // send flush request to the thread pool
inline void spdlog::async_logger::_flush()
{ {
_formatter = msg_formatter; if (auto pool_ptr = _thread_pool.lock())
_async_log_helper->set_formatter(_formatter); {
pool_ptr->post_flush(shared_from_this(), _overflow_policy);
}
else
{
throw spdlog_ex("async flush: thread pool doens't exist anymore");
}
} }
inline void spdlog::async_logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time) //
// backend functions - called from the thread pool to do the actual job
//
inline void spdlog::async_logger::_backend_log(details::log_msg &incoming_log_msg)
{ {
_formatter = std::make_shared<pattern_formatter>(pattern, pattern_time); try
_async_log_helper->set_formatter(_formatter); {
_formatter->format(incoming_log_msg);
for (auto &s : _sinks)
{
if (s->should_log(incoming_log_msg.level))
{
s->log(incoming_log_msg);
}
}
}
catch (const std::exception &ex)
{
_err_handler(ex.what());
}
catch (...)
{
_err_handler("Unknown exception in async logger " + _name);
}
} }
inline void spdlog::async_logger::_sink_it(details::log_msg &msg) inline void spdlog::async_logger::_backend_flush()
{ {
try try
{ {
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
_incr_msg_counter(msg); for (auto &sink : _sinks)
#endif
_async_log_helper->log(msg);
if (_should_flush_on(msg))
{ {
_async_log_helper->flush(false); // do async flush sink->flush();
} }
} }
catch (const std::exception &ex) catch (const std::exception &ex)
...@@ -89,7 +117,6 @@ inline void spdlog::async_logger::_sink_it(details::log_msg &msg) ...@@ -89,7 +117,6 @@ inline void spdlog::async_logger::_sink_it(details::log_msg &msg)
} }
catch (...) catch (...)
{ {
_err_handler("Unknown exception in logger " + _name); _err_handler("Unknown exception in async logger " + _name);
throw;
} }
} }
...@@ -30,8 +30,8 @@ struct log_msg ...@@ -30,8 +30,8 @@ struct log_msg
} }
log_msg(const log_msg &other) = delete; log_msg(const log_msg &other) = delete;
log_msg &operator=(log_msg &&other) = delete;
log_msg(log_msg &&other) = delete; log_msg(log_msg &&other) = delete;
log_msg &operator=(log_msg &&other) = delete;
const std::string *logger_name{nullptr}; const std::string *logger_name{nullptr};
level::level_enum level; level::level_enum level;
...@@ -40,7 +40,7 @@ struct log_msg ...@@ -40,7 +40,7 @@ struct log_msg
fmt::MemoryWriter raw; fmt::MemoryWriter raw;
fmt::MemoryWriter formatted; fmt::MemoryWriter formatted;
size_t msg_id{0}; size_t msg_id{0};
// wrap this range with color codes // info about wrapping the formatted text with color
size_t color_range_start{0}; size_t color_range_start{0};
size_t color_range_end{0}; size_t color_range_end{0};
}; };
......
...@@ -42,12 +42,12 @@ inline spdlog::logger::~logger() = default; ...@@ -42,12 +42,12 @@ inline spdlog::logger::~logger() = default;
inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter) inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
{ {
_set_formatter(std::move(msg_formatter)); _formatter = std::move(msg_formatter);
} }
inline void spdlog::logger::set_pattern(const std::string &pattern, pattern_time_type pattern_time) inline void spdlog::logger::set_pattern(const std::string &pattern, pattern_time_type pattern_time)
{ {
_set_pattern(pattern, pattern_time); _formatter = std::make_shared<pattern_formatter>(pattern, pattern_time);
} }
template<typename... Args> template<typename... Args>
...@@ -282,11 +282,22 @@ inline spdlog::log_err_handler spdlog::logger::error_handler() ...@@ -282,11 +282,22 @@ inline spdlog::log_err_handler spdlog::logger::error_handler()
return _err_handler; return _err_handler;
} }
inline void spdlog::logger::flush()
{
_flush();
}
inline void spdlog::logger::flush_on(level::level_enum log_level) inline void spdlog::logger::flush_on(level::level_enum log_level)
{ {
_flush_level.store(log_level); _flush_level.store(log_level);
} }
inline bool spdlog::logger::_should_flush(const details::log_msg &msg)
{
auto flush_level = _flush_level.load(std::memory_order_relaxed);
return (msg.level >= flush_level) && (msg.level != level::off);
}
inline spdlog::level::level_enum spdlog::logger::level() const inline spdlog::level::level_enum spdlog::logger::level() const
{ {
return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed)); return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
...@@ -314,23 +325,13 @@ inline void spdlog::logger::_sink_it(details::log_msg &msg) ...@@ -314,23 +325,13 @@ inline void spdlog::logger::_sink_it(details::log_msg &msg)
} }
} }
if (_should_flush_on(msg)) if (_should_flush(msg))
{ {
flush(); flush();
} }
} }
inline void spdlog::logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time) inline void spdlog::logger::_flush()
{
_formatter = std::make_shared<pattern_formatter>(pattern, pattern_time);
}
inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
{
_formatter = std::move(msg_formatter);
}
inline void spdlog::logger::flush()
{ {
for (auto &sink : _sinks) for (auto &sink : _sinks)
{ {
...@@ -345,19 +346,11 @@ inline void spdlog::logger::_default_err_handler(const std::string &msg) ...@@ -345,19 +346,11 @@ inline void spdlog::logger::_default_err_handler(const std::string &msg)
{ {
return; return;
} }
_last_err_time = now;
auto tm_time = details::os::localtime(now); auto tm_time = details::os::localtime(now);
char date_buf[100]; char date_buf[100];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
details::log_msg err_msg; fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg);
err_msg.formatted.write("[*** LOG ERROR ***] [{}] [{}] [{}]{}", name(), msg, date_buf, details::os::default_eol);
sinks::stderr_sink_mt::instance()->log(err_msg);
_last_err_time = now;
}
inline bool spdlog::logger::_should_flush_on(const details::log_msg &msg)
{
const auto flush_level = _flush_level.load(std::memory_order_relaxed);
return (msg.level >= flush_level) && (msg.level != level::off);
} }
inline void spdlog::logger::_incr_msg_counter(details::log_msg &msg) inline void spdlog::logger::_incr_msg_counter(details::log_msg &msg)
......
...@@ -10,86 +10,41 @@ ...@@ -10,86 +10,41 @@
// If user requests a non existing logger, nullptr will be returned // If user requests a non existing logger, nullptr will be returned
// This class is thread safe // This class is thread safe
#include "../async_logger.h"
#include "../common.h" #include "../common.h"
#include "../details/null_mutex.h"
#include "../logger.h" #include "../logger.h"
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class thread_pool;
template<class Mutex> template<class Mutex>
class registry_t class registry_t
{ {
public: public:
using MutexT = Mutex;
registry_t<Mutex>(const registry_t<Mutex> &) = delete; registry_t<Mutex>(const registry_t<Mutex> &) = delete;
registry_t<Mutex> &operator=(const registry_t<Mutex> &) = delete; registry_t<Mutex> &operator=(const registry_t<Mutex> &) = delete;
void register_logger(std::shared_ptr<logger> logger) void register_logger(std::shared_ptr<logger> new_logger)
{
std::lock_guard<Mutex> lock(_mutex);
auto logger_name = logger->name();
throw_if_exists(logger_name);
_loggers[logger_name] = logger;
}
std::shared_ptr<logger> get(const std::string &logger_name)
{
std::lock_guard<Mutex> lock(_mutex);
auto found = _loggers.find(logger_name);
return found == _loggers.end() ? nullptr : found->second;
}
template<class It>
std::shared_ptr<logger> create(const std::string &logger_name, const It &sinks_begin, const It &sinks_end)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
auto logger_name = new_logger->name();
throw_if_exists(logger_name); throw_if_exists(logger_name);
std::shared_ptr<logger> new_logger;
if (_async_mode)
{
new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy,
_worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb);
}
else
{
new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
}
if (_formatter)
{
new_logger->set_formatter(_formatter);
}
if (_err_handler)
{
new_logger->set_error_handler(_err_handler);
}
new_logger->set_level(_level);
new_logger->flush_on(_flush_level);
// Add to registry
_loggers[logger_name] = new_logger; _loggers[logger_name] = new_logger;
return new_logger;
} }
template<class It> void register_and_init(std::shared_ptr<logger> new_logger)
std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, const It &sinks_begin,
const It &sinks_end)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
auto logger_name = new_logger->name();
throw_if_exists(logger_name); throw_if_exists(logger_name);
auto new_logger = std::make_shared<async_logger>(
logger_name, sinks_begin, sinks_end, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);
if (_formatter) if (_formatter)
{ {
...@@ -106,56 +61,28 @@ public: ...@@ -106,56 +61,28 @@ public:
// Add to registry // Add to registry
_loggers[logger_name] = new_logger; _loggers[logger_name] = new_logger;
return new_logger;
} }
void apply_all(std::function<void(std::shared_ptr<logger>)> fun) std::shared_ptr<logger> get(const std::string &logger_name)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
for (auto &l : _loggers) auto found = _loggers.find(logger_name);
{ return found == _loggers.end() ? nullptr : found->second;
fun(l.second);
}
} }
void drop(const std::string &logger_name) void set_thread_pool(std::shared_ptr<thread_pool> tp)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_loggers.erase(logger_name); _tp = std::move(tp);
} }
void drop_all() std::shared_ptr<thread_pool> get_thread_pool()
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_loggers.clear(); return _tp;
}
std::shared_ptr<logger> create(const std::string &logger_name, sinks_init_list sinks)
{
return create(logger_name, sinks.begin(), sinks.end());
}
std::shared_ptr<logger> create(const std::string &logger_name, sink_ptr sink)
{
return create(logger_name, {sink});
}
std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, sinks_init_list sinks)
{
return create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks.begin(), sinks.end());
}
std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, sink_ptr sink)
{
return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, {sink});
} }
void formatter(formatter_ptr f) void set_formatter(formatter_ptr f)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_formatter = f; _formatter = f;
...@@ -204,22 +131,30 @@ public: ...@@ -204,22 +131,30 @@ public:
_err_handler = handler; _err_handler = handler;
} }
void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb, void apply_all(std::function<void(std::shared_ptr<logger>)> fun)
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_async_mode = true; for (auto &l : _loggers)
_async_q_size = q_size; {
_overflow_policy = overflow_policy; fun(l.second);
_worker_warmup_cb = worker_warmup_cb; }
_flush_interval_ms = flush_interval_ms;
_worker_teardown_cb = worker_teardown_cb;
} }
void set_sync_mode() void drop(const std::string &logger_name)
{ {
std::lock_guard<Mutex> lock(_mutex); std::lock_guard<Mutex> lock(_mutex);
_async_mode = false; _loggers.erase(logger_name);
}
void drop_all()
{
std::lock_guard<Mutex> lock(_mutex);
_loggers.clear();
}
Mutex &tp_mutex()
{
return _tp_mutex;
} }
static registry_t<Mutex> &instance() static registry_t<Mutex> &instance()
...@@ -240,22 +175,20 @@ private: ...@@ -240,22 +175,20 @@ private:
} }
Mutex _mutex; Mutex _mutex;
Mutex _tp_mutex;
std::unordered_map<std::string, std::shared_ptr<logger>> _loggers; std::unordered_map<std::string, std::shared_ptr<logger>> _loggers;
formatter_ptr _formatter; formatter_ptr _formatter;
level::level_enum _level = level::info; level::level_enum _level = level::info;
level::level_enum _flush_level = level::off; level::level_enum _flush_level = level::off;
log_err_handler _err_handler; log_err_handler _err_handler;
bool _async_mode = false; std::shared_ptr<thread_pool> _tp;
size_t _async_q_size = 0;
async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
std::function<void()> _worker_warmup_cb;
std::chrono::milliseconds _flush_interval_ms{std::chrono::milliseconds::zero()};
std::function<void()> _worker_teardown_cb;
}; };
#ifdef SPDLOG_NO_REGISTRY_MUTEX #ifdef SPDLOG_NO_REGISTRY_MUTEX
#include "../details/null_mutex.h"
using registry = registry_t<spdlog::details::null_mutex>; using registry = registry_t<spdlog::details::null_mutex>;
#else #else
#include <mutex>
using registry = registry_t<std::mutex>; using registry = registry_t<std::mutex>;
#endif #endif
......
////
//// Copyright(c) 2015 Gabi Melman.
//// Distributed under the MIT License (http://opensource.org/licenses/MIT)
////
// //
// Copyright(c) 2015 Gabi Melman. //#pragma once
// Distributed under the MIT License (http://opensource.org/licenses/MIT) //
// ////
//// Global registry functions
#pragma once ////
//#include "../details/registry.h"
// //#include "../sinks/file_sinks.h"
// Global registry functions //#include "../sinks/stdout_sinks.h"
// //#include "../spdlog.h"
#include "../details/registry.h" //#ifdef SPDLOG_ENABLE_SYSLOG
#include "../sinks/file_sinks.h" //#include "../sinks/syslog_sink.h"
#include "../sinks/stdout_sinks.h" //#endif
#include "../spdlog.h" //
#ifdef SPDLOG_ENABLE_SYSLOG //#if defined _WIN32 && !defined(__cplusplus_winrt)
#include "../sinks/syslog_sink.h" //#include "../sinks/wincolor_sink.h"
#endif //#else
//#include "../sinks/ansicolor_sink.h"
#if defined _WIN32 && !defined(__cplusplus_winrt) //#endif
#include "../sinks/wincolor_sink.h" //
#else //#ifdef __ANDROID__
#include "../sinks/ansicolor_sink.h" //#include "../sinks/android_sink.h"
#endif //#endif
//
#ifdef __ANDROID__ //#include <chrono>
#include "../sinks/android_sink.h" //#include <functional>
#endif //#include <memory>
//#include <string>
#include <chrono> //
#include <functional> // inline void spdlog::register_logger(std::shared_ptr<logger> logger)
#include <memory> //{
#include <string> // return details::registry::instance().register_logger(std::move(logger));
//}
inline void spdlog::register_logger(std::shared_ptr<logger> logger) //
{ //
return details::registry::instance().register_logger(std::move(logger)); // inline void spdlog::drop(const std::string &name)
} //{
// details::registry::instance().drop(name);
inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string &name) //}
{ //
return details::registry::instance().get(name); //// Create multi/single threaded simple file logger
} // inline std::shared_ptr<spdlog::logger> spdlog::basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate)
//{
inline void spdlog::drop(const std::string &name) // return create_and_register<sinks::simple_file_sink_mt>(logger_name, filename, truncate);
{ //}
details::registry::instance().drop(name); //
} // inline std::shared_ptr<spdlog::logger> spdlog::basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate)
//{
// Create multi/single threaded simple file logger // return create_and_register<sinks::simple_file_sink_st>(logger_name, filename, truncate);
inline std::shared_ptr<spdlog::logger> spdlog::basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate) //}
{ //
return create<spdlog::sinks::simple_file_sink_mt>(logger_name, filename, truncate); //// Create multi/single threaded rotating file logger
} // inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(
// const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
inline std::shared_ptr<spdlog::logger> spdlog::basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate) //{
{ // return create_and_register<sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files);
return create<spdlog::sinks::simple_file_sink_st>(logger_name, filename, truncate); //}
} //
// inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(
// Create multi/single threaded rotating file logger // const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt( //{
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files) // return create_and_register<sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files);
{ //}
return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files); //
} //// Create file logger which creates new file at midnight):
// inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(
inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st( // const std::string &logger_name, const filename_t &filename, int hour, int minute)
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files) //{
{ // return create_and_register<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute);
return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files); //}
} //
// inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(
// Create file logger which creates new file at midnight): // const std::string &logger_name, const filename_t &filename, int hour, int minute)
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt( //{
const std::string &logger_name, const filename_t &filename, int hour, int minute) // return create_and_register<sinks::daily_file_sink_st>(logger_name, filename, hour, minute);
{ //}
return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, hour, minute); //
} ////
//// stdout/stderr loggers
inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st( ////
const std::string &logger_name, const filename_t &filename, int hour, int minute) // inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string &logger_name)
{ //{
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, hour, minute); //
} // auto new_logger = std::make_shared<logger>(logger_name, sinks::stdout_sink_mt::instance());
// details::registry::instance().register_and_init(new_logger);
// // return new_logger;
// stdout/stderr loggers // //return details::registry::instance().create(logger_name, sinks::stdout_sink_mt::instance());
// //}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string &logger_name) //
{ // inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string &logger_name)
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance()); //{
} // auto new_logger = std::make_shared<logger>(logger_name, sinks::stdout_sink_st::instance());
// details::registry::instance().register_and_init(new_logger);
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string &logger_name) // return new_logger;
{ //}
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance()); //
} // inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string &logger_name)
//{
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string &logger_name) // auto new_logger = std::make_shared<logger>(logger_name, sinks::stderr_sink_mt::instance());
{ // details::registry::instance().register_and_init(new_logger);
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance()); // return new_logger;
} //}
//
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string &logger_name) // inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string &logger_name)
{ //{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance()); // auto new_logger = std::make_shared<logger>(logger_name, sinks::stderr_sink_st::instance());
} // details::registry::instance().register_and_init(new_logger);
// return new_logger;
// //}
// stdout/stderr color loggers //
// ////
#if defined _WIN32 && !defined(__cplusplus_winrt) //// stdout/stderr color loggers
////
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string &logger_name) //#if defined _WIN32 && !defined(__cplusplus_winrt)
{ //
auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>(); // inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string &logger_name)
return spdlog::details::registry::instance().create(logger_name, sink); //{
} // return create_and_register<sinks::wincolor_stdout_sink_mt>(logger_name);
//}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string &logger_name) //
{ // inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string &logger_name)
auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_st>(); //{
return spdlog::details::registry::instance().create(logger_name, sink); // return create_and_register<sinks::wincolor_stdout_sink_st>(logger_name);
} //}
//
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string &logger_name) // inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string &logger_name)
{ //{
auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_mt>(); // return create_and_register<sinks::wincolor_stderr_sink_mt>(logger_name);
return spdlog::details::registry::instance().create(logger_name, sink); //}
} //
// inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name)
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name) //{
{ //
auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>(); // return create_and_register<sinks::wincolor_stderr_sink_st>(logger_name);
return spdlog::details::registry::instance().create(logger_name, sink); //}
} //
//#else // ansi terminal colors
#else // ansi terminal colors //
//
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string &logger_name) // inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string &logger_name)
{ //{
auto sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>(); // return create_and_register<sinks::ansicolor_stdout_sink_mt>(logger_name);
return spdlog::details::registry::instance().create(logger_name, sink); //}
} //
// inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string &logger_name)
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string &logger_name) //{
{ // return create_and_register<sinks::ansicolor_stdout_sink_st>(logger_name);
auto sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_st>(); //}
return spdlog::details::registry::instance().create(logger_name, sink); //
} // inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string &logger_name)
//{
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string &logger_name) // return create_and_register<sinks::ansicolor_stderr_sink_mt>(logger_name);
{ //}
auto sink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_mt>(); //
return spdlog::details::registry::instance().create(logger_name, sink); // inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name)
} //{
// return create_and_register<sinks::ansicolor_stderr_sink_st>(logger_name);
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name) //}
{ //#endif
auto sink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_st>(); //
return spdlog::details::registry::instance().create(logger_name, sink); //#ifdef SPDLOG_ENABLE_SYSLOG
} //// Create syslog logger
#endif // inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(
// const std::string &logger_name, const std::string &syslog_ident, int syslog_option, int syslog_facility) {
#ifdef SPDLOG_ENABLE_SYSLOG // return create_and_register<sinks::syslog_sink>(logger_name, syslog_ident, syslog_option, syslog_facility);
// Create syslog logger //}
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger( //#endif
const std::string &logger_name, const std::string &syslog_ident, int syslog_option, int syslog_facility) //
{ //#ifdef __ANDROID__
return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option, syslog_facility); // inline std::shared_ptr<spdlog::logger> spdlog::android_logger(const std::string &logger_name, const std::string &tag)
} //{
#endif // return create_and_register<sinks::android_sink>(logger_name, tag);
//}
#ifdef __ANDROID__ //#endif
inline std::shared_ptr<spdlog::logger> spdlog::android_logger(const std::string &logger_name, const std::string &tag) //
{ //
return create<spdlog::sinks::android_sink>(logger_name, tag); //
} //
#endif // inline void spdlog::flush_on(level::level_enum log_level)
//{
// Create and register a logger a single sink // details::registry::instance().flush_on(log_level);
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, const spdlog::sink_ptr &sink) //}
{ //
return details::registry::instance().create(logger_name, sink); // inline void spdlog::set_error_handler(log_err_handler handler)
} //{
// details::registry::instance().set_error_handler(std::move(handler));
// Create logger with multiple sinks //}
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, spdlog::sinks_init_list sinks) //
{ // inline void spdlog::apply_all(std::function<void(std::shared_ptr<logger>)> fun)
return details::registry::instance().create(logger_name, sinks); //{
} // details::registry::instance().apply_all(std::move(fun));
//}
template<typename Sink, typename... Args> //
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, Args... args) // inline void spdlog::drop_all()
{ //{
sink_ptr sink = std::make_shared<Sink>(args...); // details::registry::instance().drop_all();
return details::registry::instance().create(logger_name, {sink}); //}
}
template<class It>
inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, const It &sinks_begin, const It &sinks_end)
{
return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
}
// Create and register an async logger with a single sink
inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, const sink_ptr &sink, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{
return details::registry::instance().create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sink);
}
// Create and register an async logger with multiple sinks
inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,
const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{
return details::registry::instance().create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks);
}
template<class It>
inline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, const It &sinks_begin, const It &sinks_end,
size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,
const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)
{
return details::registry::instance().create_async(
logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks_begin, sinks_end);
}
inline void spdlog::set_formatter(spdlog::formatter_ptr f)
{
details::registry::instance().formatter(std::move(f));
}
inline void spdlog::set_pattern(const std::string &format_string)
{
return details::registry::instance().set_pattern(format_string);
}
inline void spdlog::set_level(level::level_enum log_level)
{
return details::registry::instance().set_level(log_level);
}
inline void spdlog::flush_on(level::level_enum log_level)
{
return details::registry::instance().flush_on(log_level);
}
inline void spdlog::set_error_handler(log_err_handler handler)
{
return details::registry::instance().set_error_handler(std::move(handler));
}
inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy,
const std::function<void()> &worker_warmup_cb, const std::chrono::milliseconds &flush_interval_ms,
const std::function<void()> &worker_teardown_cb)
{
details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);
}
inline void spdlog::set_sync_mode()
{
details::registry::instance().set_sync_mode();
}
inline void spdlog::apply_all(std::function<void(std::shared_ptr<logger>)> fun)
{
details::registry::instance().apply_all(std::move(fun));
}
inline void spdlog::drop_all()
{
details::registry::instance().drop_all();
}
...@@ -785,7 +785,7 @@ inline typename MakeUnsigned<Int>::Type to_unsigned(Int value) ...@@ -785,7 +785,7 @@ inline typename MakeUnsigned<Int>::Type to_unsigned(Int value)
// to avoid dynamic memory allocation. // to avoid dynamic memory allocation.
enum enum
{ {
INLINE_BUFFER_SIZE = 500 INLINE_BUFFER_SIZE = 500 // TODO reduce to 250
}; };
#if FMT_SECURE_SCL #if FMT_SECURE_SCL
......
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015-2108 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
...@@ -113,27 +113,23 @@ public: ...@@ -113,27 +113,23 @@ public:
void set_pattern(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local); void set_pattern(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local);
void set_formatter(formatter_ptr msg_formatter); void set_formatter(formatter_ptr msg_formatter);
// automatically call flush() if message level >= log_level void flush();
void flush_on(level::level_enum log_level); void flush_on(level::level_enum log_level);
virtual void flush();
const std::vector<sink_ptr> &sinks() const; const std::vector<sink_ptr> &sinks() const;
// error handler // error handler
virtual void set_error_handler(log_err_handler err_handler); void set_error_handler(log_err_handler err_handler);
virtual log_err_handler error_handler(); log_err_handler error_handler();
protected: protected:
virtual void _sink_it(details::log_msg &msg); virtual void _sink_it(details::log_msg &msg);
virtual void _set_pattern(const std::string &pattern, pattern_time_type pattern_time); virtual void _flush();
virtual void _set_formatter(formatter_ptr msg_formatter);
// default error handler: print the error to stderr with the max rate of 1 message/minute bool _should_flush(const details::log_msg &msg);
virtual void _default_err_handler(const std::string &msg);
// return true if the given message level should trigger a flush // default error handler: print the error to stderr with the max rate of 1 message/minute
bool _should_flush_on(const details::log_msg &msg); void _default_err_handler(const std::string &msg);
// increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)) // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER))
void _incr_msg_counter(details::log_msg &msg); void _incr_msg_counter(details::log_msg &msg);
......
...@@ -94,7 +94,7 @@ protected: ...@@ -94,7 +94,7 @@ protected:
// after color range // after color range
_print_range(msg, msg.color_range_end, msg.formatted.size()); _print_range(msg, msg.color_range_end, msg.formatted.size());
} }
else else // no color
{ {
_print_range(msg, 0, msg.formatted.size()); _print_range(msg, 0, msg.formatted.size());
} }
......
...@@ -23,12 +23,6 @@ class stdout_sink SPDLOG_FINAL : public base_sink<Mutex> ...@@ -23,12 +23,6 @@ class stdout_sink SPDLOG_FINAL : public base_sink<Mutex>
public: public:
explicit stdout_sink() = default; explicit stdout_sink() = default;
static std::shared_ptr<MyType> instance()
{
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
return instance;
}
protected: protected:
void _sink_it(const details::log_msg &msg) override void _sink_it(const details::log_msg &msg) override
{ {
...@@ -53,12 +47,6 @@ class stderr_sink SPDLOG_FINAL : public base_sink<Mutex> ...@@ -53,12 +47,6 @@ class stderr_sink SPDLOG_FINAL : public base_sink<Mutex>
public: public:
explicit stderr_sink() = default; explicit stderr_sink() = default;
static std::shared_ptr<MyType> instance()
{
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
return instance;
}
protected: protected:
void _sink_it(const details::log_msg &msg) override void _sink_it(const details::log_msg &msg) override
{ {
......
// //
// Copyright(c) 2015 Gabi Melman. // Copyright(c) 2015-2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
// //
// spdlog main header file. // spdlog main header file.
...@@ -7,9 +7,23 @@ ...@@ -7,9 +7,23 @@
#pragma once #pragma once
#include "details/registry.h"
#include "sinks/file_sinks.h"
#include "sinks/stdout_sinks.h"
#include "common.h" #include "common.h"
#include "logger.h" #include "logger.h"
#if defined _WIN32
#include "sinks/wincolor_sink.h"
#else
#include "sinks/ansicolor_sink.h"
#endif
#ifdef __ANDROID__
#include "sinks/android_sink.h"
#endif
#include <chrono> #include <chrono>
#include <functional> #include <functional>
#include <memory> #include <memory>
...@@ -17,157 +31,213 @@ ...@@ -17,157 +31,213 @@
namespace spdlog { namespace spdlog {
// Default logger factory- creates synchronous loggers
struct default_factory
{
template<typename Sink, typename... SinkArgs>
static std::shared_ptr<spdlog::logger> create(const std::string &logger_name, SinkArgs &&... args)
{
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<logger>(logger_name, std::move(sink));
details::registry::instance().register_and_init(new_logger);
return new_logger;
}
};
// Create and register a logger with a templated sink type
// The logger's level, formatter and flush level will be set according the global settings.
// Example:
// spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59);
template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create(const std::string &logger_name, SinkArgs &&... sink_args)
{
return default_factory::create<Sink>(logger_name, std::forward<SinkArgs>(sink_args)...);
}
// //
// Return an existing logger or nullptr if a logger with such name doesn't exist. // Return an existing logger or nullptr if a logger with such name doesn't exist.
// example: spdlog::get("my_logger")->info("hello {}", "world"); // example: spdlog::get("my_logger")->info("hello {}", "world");
// //
std::shared_ptr<logger> get(const std::string &name); inline std::shared_ptr<logger> get(const std::string &name)
{
return details::registry::instance().get(name);
}
// //
// Set global formatting // Set global formatting
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); // example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
// //
void set_pattern(const std::string &format_string); inline void set_pattern(const std::string &format_string)
void set_formatter(formatter_ptr f); {
details::registry::instance().set_pattern(format_string);
}
inline void set_formatter(formatter_ptr f)
{
details::registry::instance().set_formatter(std::move(f));
}
// //
// Set global logging level // Set global logging level
// //
void set_level(level::level_enum log_level); inline void set_level(level::level_enum log_level)
{
details::registry::instance().set_level(log_level);
}
// //
// Set global flush level // Set global flush level
// //
void flush_on(level::level_enum log_level); inline void flush_on(level::level_enum log_level)
{
details::registry::instance().flush_on(log_level);
}
// //
// Set global error handler // Set global error handler
// //
void set_error_handler(log_err_handler handler); inline void set_error_handler(log_err_handler handler)
{
details::registry::instance().set_error_handler(std::move(handler));
}
// // Register the given logger with the given name
// Turn on async mode (off by default) and set the queue size for each async_logger. inline void register_logger(std::shared_ptr<logger> logger)
// effective only for loggers created after this call. {
// queue_size: size of queue (must be power of 2): details::registry::instance().register_logger(std::move(logger));
// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction. }
//
// async_overflow_policy (optional, block_retry by default): // Apply a user defined function on all registered loggers
// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry. // Example:
// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows. // spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();});
// inline void apply_all(std::function<void(std::shared_ptr<logger>)> fun)
// worker_warmup_cb (optional): {
// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity) details::registry::instance().apply_all(std::move(fun));
// }
// worker_teardown_cb (optional):
// callback function that will be called in worker thread upon exit // Drop the reference to the given logger
// inline void drop(const std::string &name)
void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, {
const std::function<void()> &worker_warmup_cb = nullptr, details::registry::instance().drop(name);
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(), }
const std::function<void()> &worker_teardown_cb = nullptr);
// Turn off async mode // Drop all references from the registry
void set_sync_mode(); inline void drop_all()
{
details::registry::instance().drop_all();
}
// //
// Create and register multi/single threaded basic file logger. // Create and register multi/single threaded basic file logger.
// Basic logger simply writes to given file without any limitations or rotations. // Basic logger simply writes to given file without any limitations or rotations.
// //
std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false); template<typename Factory = default_factory>
std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false); inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)
{
return Factory::template create<sinks::simple_file_sink_mt>(logger_name, filename, truncate);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)
{
return Factory::template create<sinks::simple_file_sink_st>(logger_name, filename, truncate);
}
// //
// Create and register multi/single threaded rotating file logger // Create and register multi/single threaded rotating file logger
// //
std::shared_ptr<logger> rotating_logger_mt( template<typename Factory = default_factory>
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files); inline std::shared_ptr<logger> rotating_logger_mt(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
std::shared_ptr<logger> rotating_logger_st( {
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files); return Factory::template create<sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> rotating_logger_st(
const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)
{
return Factory::template create<sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files);
}
// //
// Create file logger which creates new file on the given time (default in midnight): // Create file logger which creates new file on the given time (default in midnight):
// //
std::shared_ptr<logger> daily_logger_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0); template<typename Factory = default_factory>
std::shared_ptr<logger> daily_logger_st(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0); inline std::shared_ptr<logger> daily_logger_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0)
{
return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute);
}
template<typename Factory = default_factory>
inline std::shared_ptr<logger> daily_logger_st(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0)
{
return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute);
}
///////////////////////////////////////////////////////////////////////////////
// stdout and stderr loggers
// //
// Create and register stdout/stderr loggers // multi threaded and colored:
// spdlog::console<stdout_color_mt>("name")
// spdlog::console<stderr_color_mt>("name")
// //
std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name); // single threaded and colored:
std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name); // spdlog::console<stdout_color_st>("name")
std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name); // spdlog::console<stderr_color_st>("name")
std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name);
// //
// Create and register colored stdout/stderr loggers // multi threaded, no color:
// spdlog::console<stdout_mt>("name")
// spdlog::console<stderr_mt>("name")
// //
std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name); // single threaded, no color:
std::shared_ptr<logger> stdout_color_st(const std::string &logger_name); // spdlog::console<stdout_st>("name")
std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name); // spdlog::console<stderr_st>("name")
std::shared_ptr<logger> stderr_color_st(const std::string &logger_name); ///////////////////////////////////////////////////////////////////////////////
#if defined _WIN32 // window color console
using stdout_color_mt = sinks::wincolor_stdout_sink_mt;
using stdout_color_st = sinks::wincolor_stdout_sink_st;
using stderr_color_mt = sinks::wincolor_stderr_sink_mt;
using stderr_color_st = sinks::wincolor_stderr_sink_st;
#else // ansi color console
using stdout_color_mt = sinks::ansicolor_stdout_sink_mt;
using stdout_color_st = sinks::ansicolor_stdout_sink_st;
using stderr_color_mt = sinks::ansicolor_stderr_sink_mt;
using stderr_color_st = sinks::ansicolor_stderr_sink_st;
#endif
// no color console
using stdout_mt = sinks::stdout_sink_mt;
using stdout_st = sinks::stdout_sink_st;
using stderr_mt = sinks::stderr_sink_mt;
using stderr_st = sinks::stderr_sink_st;
template<typename Sink, typename Factory = default_factory>
inline std::shared_ptr<logger> console(const std::string &logger_name)
{
return Factory::template create<Sink>(logger_name);
}
//
// Create and register a syslog logger
//
#ifdef SPDLOG_ENABLE_SYSLOG #ifdef SPDLOG_ENABLE_SYSLOG
std::shared_ptr<logger> syslog_logger( // Create and register a syslog logger
const std::string &logger_name, const std::string &ident = "", int syslog_option = 0, int syslog_facilty = (1 << 3)); template<typename Factory = default_factory>
inline std::shared_ptr<logger> syslog_logger(
const std::string &logger_name, const std::string &ident = "", int syslog_option = 0, int syslog_facilty = (1 << 3))
{
return return Factory::template create<sinks::syslog_sink>(logger_name, syslog_ident, syslog_option, syslog_facility);
}
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__)
std::shared_ptr<logger> android_logger(const std::string &logger_name, const std::string &tag = "spdlog"); // Create and register android syslog logger
template<typename Factory = default_factory>
inline std::shared_ptr<logger> android_logger(const std::string &logger_name, const std::string &tag = "spdlog")
{
return return Factory::template create<sinks::android_sink>(logger_name, tag);
}
#endif #endif
// Create and register a logger with a single sink
std::shared_ptr<logger> create(const std::string &logger_name, const sink_ptr &sink);
// Create and register a logger with multiple sinks
std::shared_ptr<logger> create(const std::string &logger_name, sinks_init_list sinks);
template<class It>
std::shared_ptr<logger> create(const std::string &logger_name, const It &sinks_begin, const It &sinks_end);
// Create and register a logger with templated sink type
// Example:
// spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename");
template<typename Sink, typename... Args>
std::shared_ptr<spdlog::logger> create(const std::string &logger_name, Args... args);
// Create and register an async logger with a single sink
std::shared_ptr<logger> create_async(const std::string &logger_name, const sink_ptr &sink, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()> &worker_warmup_cb = nullptr,
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
const std::function<void()> &worker_teardown_cb = nullptr);
// Create and register an async logger with multiple sinks
std::shared_ptr<logger> create_async(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()> &worker_warmup_cb = nullptr,
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
const std::function<void()> &worker_teardown_cb = nullptr);
template<class It>
std::shared_ptr<logger> create_async(const std::string &logger_name, const It &sinks_begin, const It &sinks_end, size_t queue_size,
const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
const std::function<void()> &worker_warmup_cb = nullptr,
const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
const std::function<void()> &worker_teardown_cb = nullptr);
// Register the given logger with the given name
void register_logger(std::shared_ptr<logger> logger);
// Apply a user defined function on all registered loggers
// Example:
// spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();});
void apply_all(std::function<void(std::shared_ptr<logger>)> fun);
// Drop the reference to the given logger
void drop(const std::string &name);
// Drop all references from the registry
void drop_all();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// //
// Trace & Debug can be switched on/off at compile time for zero cost debug statements. // Trace & Debug can be switched on/off at compile time for zero cost debug statements.
...@@ -200,5 +270,3 @@ void drop_all(); ...@@ -200,5 +270,3 @@ void drop_all();
#endif #endif
} // namespace spdlog } // namespace spdlog
#include "details/spdlog_impl.h"
...@@ -67,10 +67,11 @@ TEST_CASE("async_error_handler", "[errors]]") ...@@ -67,10 +67,11 @@ TEST_CASE("async_error_handler", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string err_msg("log failed with some msg"); std::string err_msg("log failed with some msg");
spdlog::set_async_mode(128);
std::string filename = "logs/simple_async_log.txt"; std::string filename = "logs/simple_async_log.txt";
{ {
auto logger = spdlog::create<spdlog::sinks::simple_file_sink_mt>("logger", filename, true); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_as<spdlog::sinks::simple_file_sink_mt>("logger", filename, true);
logger->set_error_handler([=](const std::string &msg) { logger->set_error_handler([=](const std::string &msg) {
std::ofstream ofs("logs/custom_err.txt"); std::ofstream ofs("logs/custom_err.txt");
if (!ofs) if (!ofs)
...@@ -85,8 +86,8 @@ TEST_CASE("async_error_handler", "[errors]]") ...@@ -85,8 +86,8 @@ TEST_CASE("async_error_handler", "[errors]]")
#endif #endif
logger->info("Good message #2"); logger->info("Good message #2");
spdlog::drop("logger"); // force logger to drain the queue and shutdown spdlog::drop("logger"); // force logger to drain the queue and shutdown
spdlog::set_sync_mode();
} }
spdlog::init_thread_pool(128, 1);
REQUIRE(count_lines(filename) == 2); REQUIRE(count_lines(filename) == 2);
REQUIRE(file_contents("logs/custom_err.txt") == err_msg); REQUIRE(file_contents("logs/custom_err.txt") == err_msg);
} }
...@@ -96,9 +97,9 @@ TEST_CASE("async_error_handler2", "[errors]]") ...@@ -96,9 +97,9 @@ TEST_CASE("async_error_handler2", "[errors]]")
{ {
prepare_logdir(); prepare_logdir();
std::string err_msg("This is async handler error message"); std::string err_msg("This is async handler error message");
spdlog::set_async_mode(128);
{ {
auto logger = spdlog::create<failing_sink>("failed_logger"); spdlog::init_thread_pool(128, 1);
auto logger = spdlog::create_as<failing_sink>("failed_logger");
logger->set_error_handler([=](const std::string &msg) { logger->set_error_handler([=](const std::string &msg) {
std::ofstream ofs("logs/custom_err2.txt"); std::ofstream ofs("logs/custom_err2.txt");
if (!ofs) if (!ofs)
...@@ -107,8 +108,8 @@ TEST_CASE("async_error_handler2", "[errors]]") ...@@ -107,8 +108,8 @@ TEST_CASE("async_error_handler2", "[errors]]")
}); });
logger->info("Hello failure"); logger->info("Hello failure");
spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown
spdlog::set_sync_mode();
} }
spdlog::init_thread_pool(128, 1);
REQUIRE(file_contents("logs/custom_err2.txt") == err_msg); REQUIRE(file_contents("logs/custom_err2.txt") == err_msg);
} }
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define SPDLOG_TRACE_ON #define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON #define SPDLOG_DEBUG_ON
#include "../include/spdlog/async.h"
#include "../include/spdlog/sinks/null_sink.h" #include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/ostream_sink.h" #include "../include/spdlog/sinks/ostream_sink.h"
#include "../include/spdlog/spdlog.h" #include "../include/spdlog/spdlog.h"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment