From f7dd08c2357992c1ecbe831203c04e319304c4b6 Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 26 Jan 2014 01:53:23 +0200 Subject: [PATCH] file sinks refactoring --- include/c11log/logger.h | 2 +- include/c11log/sinks/async_sink.h | 9 +-- include/c11log/sinks/base_sink.h | 15 ++-- include/c11log/sinks/file_sinks.h | 121 ++++++++++++++---------------- test/test.cpp | 41 ++++++---- 5 files changed, 93 insertions(+), 95 deletions(-) diff --git a/include/c11log/logger.h b/include/c11log/logger.h index 0ca87398..97f18b88 100644 --- a/include/c11log/logger.h +++ b/include/c11log/logger.h @@ -76,7 +76,7 @@ inline c11log::details::line_logger c11log::logger::log(c11log::level::level_enu { std::lock_guard lock(mutex_); return details::line_logger(this, msg_level); - } + } else { return details::line_logger(nullptr); diff --git a/include/c11log/sinks/async_sink.h b/include/c11log/sinks/async_sink.h index 4aee4f76..0780794c 100644 --- a/include/c11log/sinks/async_sink.h +++ b/include/c11log/sinks/async_sink.h @@ -32,7 +32,6 @@ protected: private: c11log::logger::sinks_vector_t sinks_; std::atomic active_ { true }; - const std::chrono::seconds push_pop_timeout_; c11log::details::blocking_queue q_; std::thread back_thread_; //Clear all remaining messages(if any), stop the back_thread_ and join it @@ -47,7 +46,6 @@ private: inline c11log::sinks::async_sink::async_sink(const std::size_t max_queue_size) :q_(max_queue_size), - push_pop_timeout_(std::chrono::seconds(2)), back_thread_(&async_sink::thread_loop_, this) {} @@ -57,19 +55,20 @@ inline c11log::sinks::async_sink::~async_sink() } inline void c11log::sinks::async_sink::sink_it_(const std::string& msg) { - q_.push(msg, push_pop_timeout_); + q_.push(msg); } inline void c11log::sinks::async_sink::thread_loop_() { std::string msg; + auto pop_timeout = std::chrono::seconds(1); while (active_) { - if (q_.pop(msg, push_pop_timeout_)) + if (q_.pop(msg, pop_timeout)) { for (auto &sink : sinks_) { - sink->log(msg, _level); + sink->log(msg, static_cast(_level.load())); if (!active_) return; } diff --git a/include/c11log/sinks/base_sink.h b/include/c11log/sinks/base_sink.h index bf444729..21717a75 100644 --- a/include/c11log/sinks/base_sink.h +++ b/include/c11log/sinks/base_sink.h @@ -1,8 +1,7 @@ #pragma once #include -#include -#include +#include #include "../formatters/formatters.h" #include "../level.h" @@ -11,33 +10,29 @@ namespace c11log { namespace sinks { class base_sink { public: - base_sink() = default; + base_sink() = default; base_sink(level::level_enum l):_level(l) {}; virtual ~base_sink() = default; - + base_sink(const base_sink&) = delete; base_sink& operator=(const base_sink&) = delete; void log(const std::string &msg, level::level_enum level) { if (level >= _level) { - std::lock_guard lock(mutex_); - if (level >= _level) - sink_it_(msg); + sink_it_(msg); } }; void set_level(level::level_enum level) { - std::lock_guard lock(mutex_); _level = level; } protected: virtual void sink_it_(const std::string& msg) = 0; - level::level_enum _level = level::INFO; - std::mutex mutex_; + std::atomic _level = level::INFO; }; class null_sink:public base_sink { diff --git a/include/c11log/sinks/file_sinks.h b/include/c11log/sinks/file_sinks.h index a811dffa..de237061 100644 --- a/include/c11log/sinks/file_sinks.h +++ b/include/c11log/sinks/file_sinks.h @@ -2,6 +2,8 @@ #include #include +#include + #include "../logger.h" #include "../log_exception.h" @@ -14,7 +16,7 @@ namespace sinks { /* * Trivial file sink with single file as target */ -class simple_file_sink:base_sink { +class simple_file_sink : public base_sink { public: simple_file_sink(const std::string &filename, const std::string& extension = "txt") { @@ -25,38 +27,21 @@ public: protected: void sink_it_(const std::string& msg) override { + std::lock_guard lock(mutex_); _ofstream << msg; _ofstream.flush(); } - +private: + std::mutex mutex_; std::ofstream _ofstream; }; + /* - * Rotating file sinks. Close and open new file at some point - */ -namespace details { -class rotating_file_sink_base:public base_sink { -public: - rotating_file_sink_base() - {} - virtual ~rotating_file_sink_base() - {} -protected: - virtual void sink_it_(const std::string& msg) override - { - if (_should_rotate()) - _rotate(); - _ofstream << msg; - _ofstream.flush(); - } - virtual bool _should_rotate() const = 0; - virtual void _rotate() = 0; - std::ofstream _ofstream; -}; -} -class rotating_file_sink:public details::rotating_file_sink_base { + * Thread safe, size limited file sink +*/ +class rotating_file_sink : public base_sink { public: rotating_file_sink(const std::string &base_filename, const std::string &extension, size_t max_size, size_t max_files): _base_filename(base_filename), @@ -70,37 +55,20 @@ public: } protected: - virtual void sink_it_(const std::string& msg) override + void sink_it_(const std::string& msg) override { + std::lock_guard lock(mutex_); _current_size += msg.length(); - rotating_file_sink_base::sink_it_(msg); - } - - bool _should_rotate() const override - { - return _current_size >= _max_size; - } - - // Rotate old files: - // log.n-1.txt -> log.n.txt - // log n-2.txt -> log.n-1.txt - // ... - // log.txt -> log.1.txt - void _rotate() override - { - _ofstream.close(); - _current_size = 0; - //Remove oldest file - for (auto i = _max_files; i > 0; --i) { - auto src = _calc_filename(_base_filename, i - 1, _extension); - auto target = _calc_filename(_base_filename, i, _extension); - if (i == _max_files) - std::remove(target.c_str()); - std::rename(src.c_str(), target.c_str()); + if (_current_size > _max_size) + { + _rotate(); + _current_size = msg.length(); } - - _ofstream.open(_calc_filename(_base_filename, 0, _extension)); + _ofstream << msg; + _ofstream.flush(); } + + private: static std::string _calc_filename(const std::string& filename, std::size_t index, const std::string& extension) { @@ -111,19 +79,42 @@ private: oss << filename << "." << extension; return oss.str(); } + + + // Rotate old files: + // log.n-1.txt -> log.n.txt + // log n-2.txt -> log.n-1.txt + // ... + // log.txt -> log.1.txt + void _rotate() + { + _ofstream.close(); + //Remove oldest file + for (auto i = _max_files; i > 0; --i) { + auto src = _calc_filename(_base_filename, i - 1, _extension); + auto target = _calc_filename(_base_filename, i, _extension); + if (i == _max_files) + std::remove(target.c_str()); + std::rename(src.c_str(), target.c_str()); + } + _ofstream.open(_calc_filename(_base_filename, 0, _extension)); + } + std::string _base_filename; std::string _extension; std::size_t _max_size; std::size_t _max_files; std::size_t _current_size; std::size_t _index; + std::ofstream _ofstream; + std::mutex mutex_; }; /* - * File sink that closes the log file at midnight and opens new one + * Thread safe file sink that closes the log file at midnight and opens new one */ -class midnight_file_sink:public details::rotating_file_sink_base { +class midnight_file_sink:public base_sink { public: midnight_file_sink(const std::string& base_filename, const std::string& extension = "txt"): _base_filename(base_filename), @@ -135,16 +126,17 @@ public: } protected: - bool _should_rotate() const override + void sink_it_(const std::string& msg) override { - return std::chrono::system_clock::now() >= _midnight_tp; - } - void _rotate() override - { - _midnight_tp = _calc_midnight_tp(); - _ofstream.close(); - _ofstream.open(_calc_filename(_base_filename, _extension)); - + std::lock_guard lock(mutex_); + if (std::chrono::system_clock::now() >= _midnight_tp) + { + _ofstream.close(); + _ofstream.open(_calc_filename(_base_filename, _extension)); + _midnight_tp = _calc_midnight_tp(); + } + _ofstream << msg; + _ofstream.flush(); } private: @@ -167,9 +159,12 @@ private: oss << basename << std::put_time(&now_tm, ".%Y-%m-%d.") << extension; return oss.str(); } + std::string _base_filename; std::string _extension; std::chrono::system_clock::time_point _midnight_tp; + std::ofstream _ofstream; + std::mutex mutex_; }; } } \ No newline at end of file diff --git a/test/test.cpp b/test/test.cpp index dd2b6d34..36b77eb0 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -8,27 +8,36 @@ int main(int argc, char* argv[]) { + + auto null_sink = std::make_shared(); + auto async = std::make_shared(100); + auto fsink = std::make_shared("newlog", "txt", 1024*1024*10 , 2); + + async->add_sink(fsink); + c11log::logger logger("test"); - - auto screen_sink = std::make_shared(); - auto file_sink = std::make_shared("logtest"); - auto async = std::make_shared(1000); - async->add_sink(file_sink); logger.add_sink(async); - //logger.add_sink(file_sink); - - auto fn = [&logger]() + std::atomic counter { 0 }; + auto counter_ptr = &counter; + for (int i = 0; i < 4; i++) { - logger.info() << "Hello logger!"; - }; - utils::bench("test log", std::chrono::seconds(3), fn); - logger.info() << "bye"; - utils::bench("shutdown", [&async]() { - async->shutdown(std::chrono::seconds(10)); - }); - + new std::thread([&logger, counter_ptr]() { + while (true) + { + logger.info() << "Hello from thread" << std::this_thread::get_id(); + (*counter_ptr)++; + } + }); + } + while (true) + { + counter = 0; + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Counter = " << utils::format(counter.load()) << std::endl; + } + async->shutdown(std::chrono::seconds(10)); return 0; }