diff --git a/example/example.cpp b/example/example.cpp index b2bfefdc..a31d8daf 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -9,62 +9,37 @@ #include "utils.h" -std::atomic log_count; -std::atomic active; - -using std::chrono::seconds; - -void logging_thread() -{ - auto &logger = c11log::get_logger("async"); - while(active) { - logger.info()<<"Hello logger!"; - ++log_count; - } -} - - -void testlog(int threads) -{ - - active = true; - - for(int i = 0; i < threads; i++) - new std::thread(std::bind(logging_thread)); - - while(active) { - using std::endl; - using std::cout; - using utils::format; - - log_count = 0; - std::this_thread::sleep_for(seconds(1)); - cout << "Logs/sec =\t" << format(log_count.load()) << endl; - } -} +using std::cout; +using std::endl; +using namespace std::chrono; +using namespace c11log; +using namespace utils; int main(int argc, char* argv[]) { - if(argc || argv) {}; - using namespace std::chrono; - using namespace c11log; - using namespace utils; - using std::cout; - using std::endl; + auto fsink = std::make_shared("log", "txt", 1024*1024*50 , 5, seconds(1)); - auto &my_logger = get_logger("example"); + //auto &my_logger = get_logger("example"); auto null_sink = std::make_shared(); //auto async = std::make_shared(1000); //my_logger.add_sink(fsink); - my_logger.add_sink(null_sink); + //my_logger.add_sink(null_sink); - auto &cout_logger = get_logger("cout"); - cout_logger.add_sink(sinks::stdout_sink()); - cout_logger.info() << "Hello cout logger!"; - + + + logger cout_logger ( + "cout", + {null_sink, sinks::stdout_sink(), fsink}); + + cout_logger.info() << "Hello cout logger!"; + + logger log2 {sinks::stdout_sink()}; + log2.error() << "Cool shit" << "!!!"; + return 0; + /* auto start = system_clock::now(); const unsigned int howmany = 5000000; @@ -80,7 +55,7 @@ int main(int argc, char* argv[]) return 0; - + */ /* if(argc !=3) { std::cerr << "Usage: " << argv[0] << " qsize, threads" << std::endl; diff --git a/include/c11log/common_types.h b/include/c11log/common_types.h index d7d17e64..1ce1431d 100644 --- a/include/c11log/common_types.h +++ b/include/c11log/common_types.h @@ -21,7 +21,7 @@ const char* to_str(level_enum l); } } -static const char* level_names[] { "Debug", "Info", "Warning", "Error", "Fatal" }; +static const char* level_names[] { "debug", "info", "warning", "error", "fatal" }; inline const char* c11log::level::to_str(c11log::level::level_enum l) { return level_names[l]; diff --git a/include/c11log/details/factory.h b/include/c11log/details/factory.h index 52c5603f..8da585f5 100644 --- a/include/c11log/details/factory.h +++ b/include/c11log/details/factory.h @@ -13,29 +13,45 @@ namespace details class factory { public: - typedef std::shared_ptr logger_ptr; - typedef std::unordered_map logger_map; - logger_ptr get_logger(const std::string &name); + using logger_ptr = std::shared_ptr; + using logger_map = std::unordered_map; + void add_logger(const std::string& name, logger_ptr); + logger_ptr get_logger(const std::string &name); static c11log::details::factory& instance(); private: + std::mutex _loggers_mutex; logger_map _loggers; - std::mutex _loggers_mutex; + }; } } +inline void c11log::details::factory::add_logger(const std::string& name, logger_ptr logger_p) +{ + std::lock_guard lock(_loggers_mutex); + _loggers.insert(logger_map::value_type(name, logger_p)); +} + inline c11log::details::factory::logger_ptr c11log::details::factory::get_logger(const std::string &name) { std::lock_guard lock(_loggers_mutex); - auto found = _loggers.find(name); + + auto found = _loggers.find(name); + if (found != _loggers.end()) + return found->second; + else + return logger_ptr(nullptr); + /* + auto found = _loggers.find(name); + if (found == _loggers.end()) { auto new_logger_ptr = std::make_shared(name); _loggers.insert(std::make_pair(name, new_logger_ptr)); return new_logger_ptr; } else { return found->second; - } + }*/ } inline c11log::details::factory & c11log::details::factory::instance() diff --git a/include/c11log/details/line_logger.h b/include/c11log/details/line_logger.h index 1010bc82..bd366522 100644 --- a/include/c11log/details/line_logger.h +++ b/include/c11log/details/line_logger.h @@ -3,11 +3,15 @@ #include "../common_types.h" #include "../logger.h" #include "fast_oss.h" -#include + + +// line logger class. should be used by the logger as an rvalue only. +// aggregates logging string until the end of the line and then calls the logger upon destruction + namespace c11log { -class logger; +//class logger; namespace details { @@ -19,24 +23,27 @@ public: _oss(), _level(msg_level), _enabled(enabled) { - callback_logger->_formatter->format_header(callback_logger->_logger_name, - msg_level, - log_clock::now(), - _oss); + if(enabled) { + callback_logger->_formatter->format_header(callback_logger->_logger_name, + msg_level, + log_clock::now(), + _oss); + } } // No copy intended. Only move line_logger(const line_logger& other) = delete; + line_logger& operator=(const line_logger&) = delete; + line_logger& operator=(line_logger&&) = delete; line_logger(line_logger&& other) : _callback_logger(other._callback_logger), + // The move ctor should only be called on start of logging line, + // where no logging happened yet for this line so no need to copy the string from the other _oss(), _level(other._level) { }; - line_logger& operator=(const line_logger&) = delete; - line_logger& operator=(line_logger&&) = delete; - ~line_logger() { if (_enabled) { _oss << '\n'; @@ -46,15 +53,14 @@ public: template - line_logger& operator<<(const T& msg) { + line_logger&& operator<<(const T& msg) && { if (_enabled) _oss << msg; - return *this; + return std::move(*this); } private: logger* _callback_logger; - //std::ostringstream _oss; details::fast_oss _oss; level::level_enum _level; bool _enabled; diff --git a/include/c11log/formatter.h b/include/c11log/formatter.h index b782a33c..aa562859 100644 --- a/include/c11log/formatter.h +++ b/include/c11log/formatter.h @@ -33,7 +33,11 @@ public: // Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body void format_header(const std::string& logger_name, level::level_enum level, const log_clock::time_point& tp, std::ostream& dest) override { _format_time(tp, dest); - dest << " [" << logger_name << ":" << c11log::level::to_str(level) << "] "; + if(!logger_name.empty()) + dest << " [" << logger_name << ":" << c11log::level::to_str(level) << "] "; + else + dest << " [" << c11log::level::to_str(level) << "] "; + } private: void _format_time(const log_clock::time_point& tp, std::ostream &dest); diff --git a/include/c11log/logger.h b/include/c11log/logger.h index 45eb471a..9bd88d1e 100644 --- a/include/c11log/logger.h +++ b/include/c11log/logger.h @@ -12,10 +12,12 @@ #include "sinks/base_sink.h" #include "details/factory.h" + +//Thread safe, fast logger. +//All initialization is done in ctor only, so we get away lot of locking namespace c11log { - namespace details { class line_logger; @@ -26,33 +28,43 @@ class logger { public: - typedef std::shared_ptr sink_ptr_t; - typedef std::vector sinks_vector_t; + using sink_ptr = std::shared_ptr; + using formatter_ptr = std::shared_ptr; + using sinks_vector_t = std::vector; + using sinks_init_list = std::initializer_list; - explicit logger(const std::string& name) : + + logger(const std::string& name, formatter_ptr f, sinks_init_list sinks_list) : _logger_name(name), - _formatter(new formatters::default_formatter()), - _sinks(), - _mutex() { + _formatter(f), + _sinks(sinks_list) { //Seems that vs2013 doesnt support atomic member initialization in ctor, so its done here _atomic_level = level::INFO; } + logger(const std::string& name, sinks_init_list sinks_list) : + logger(name, std::make_shared(), sinks_list) {} + + + logger(sinks_init_list sinks_list) : + logger("", std::make_shared(), sinks_list) {} + + ~logger() = default; + //Non copybale in anyway logger(const logger&) = delete; + logger(logger&&) = delete; logger& operator=(const logger&) = delete; + logger& operator=(logger&&) = delete; - void set_name(const std::string& name); - const std::string& get_name(); - void add_sink(sink_ptr_t sink_ptr); - void remove_sink(sink_ptr_t sink_ptr); - void set_formatter(std::unique_ptr formatter); - void set_level(c11log::level::level_enum level); + void set_level(c11log::level::level_enum); c11log::level::level_enum get_level() const; - bool should_log(c11log::level::level_enum level) const; - details::line_logger log(level::level_enum level); + const std::string& get_name() const; + bool should_log(c11log::level::level_enum) const; + + details::line_logger log(level::level_enum); details::line_logger debug(); details::line_logger info(); details::line_logger warn(); @@ -63,9 +75,8 @@ private: friend details::line_logger; std::string _logger_name = ""; - std::unique_ptr _formatter; + formatter_ptr _formatter; sinks_vector_t _sinks; - std::mutex _mutex; std::atomic_int _atomic_level; void _log_it(const std::string& msg, const level::level_enum level); @@ -107,35 +118,12 @@ inline c11log::details::line_logger c11log::logger::fatal() return log(c11log::level::FATAL); } -inline void c11log::logger::set_name(const std::string& name) -{ - std::lock_guard lock(_mutex); - _logger_name = name; -} -inline const std::string& c11log::logger::get_name() +inline const std::string& c11log::logger::get_name() const { - std::lock_guard lock(_mutex); return _logger_name; } -inline void c11log::logger::add_sink(sink_ptr_t sink_ptr) -{ - std::lock_guard lock(_mutex); - _sinks.push_back(sink_ptr); -} - -inline void c11log::logger::remove_sink(sink_ptr_t sink_ptr) -{ - std::lock_guard lock(_mutex); - _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink_ptr), _sinks.end()); -} - -inline void c11log::logger::set_formatter(std::unique_ptr formatter) -{ - std::lock_guard lock(_mutex); - _formatter = std::move(formatter); -} inline void c11log::logger::set_level(c11log::level::level_enum level) { @@ -143,7 +131,7 @@ inline void c11log::logger::set_level(c11log::level::level_enum level) } inline c11log::level::level_enum c11log::logger::get_level() const -{ +{ return static_cast(_atomic_level.load()); } @@ -153,14 +141,13 @@ inline bool c11log::logger::should_log(c11log::level::level_enum level) const } inline void c11log::logger::_log_it(const std::string& msg, const level::level_enum level) { - std::lock_guard lock(_mutex); for (auto &sink : _sinks) sink->log(msg, level); } // Static factory function + inline c11log::logger& c11log::get_logger(const std::string& name) { return *(c11log::details::factory::instance().get_logger(name)); } - diff --git a/include/c11log/sinks/async_sink.h b/include/c11log/sinks/async_sink.h index 73d86d8e..6a200d15 100644 --- a/include/c11log/sinks/async_sink.h +++ b/include/c11log/sinks/async_sink.h @@ -20,8 +20,8 @@ public: explicit async_sink(const size_type max_queue_size); ~async_sink(); - void add_sink(logger::sink_ptr_t sink); - void remove_sink(logger::sink_ptr_t sink_ptr); + void add_sink(logger::sink_ptr sink); + void remove_sink(logger::sink_ptr sink_ptr); //Wait to remaining items (if any) in the queue to be written and shutdown void shutdown(const std::chrono::seconds& timeout); @@ -78,12 +78,12 @@ inline void c11log::sinks::async_sink::_thread_loop() } } -inline void c11log::sinks::async_sink::add_sink(logger::sink_ptr_t sink) +inline void c11log::sinks::async_sink::add_sink(logger::sink_ptr sink) { _sinks.push_back(sink); } -inline void c11log::sinks::async_sink::remove_sink(logger::sink_ptr_t sink_ptr) +inline void c11log::sinks::async_sink::remove_sink(logger::sink_ptr sink_ptr) { _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink_ptr), _sinks.end()); } diff --git a/include/c11log/sinks/console_sinks.h b/include/c11log/sinks/console_sinks.h index c93e753d..d42ad699 100644 --- a/include/c11log/sinks/console_sinks.h +++ b/include/c11log/sinks/console_sinks.h @@ -31,14 +31,14 @@ protected: inline std::shared_ptr& stdout_sink () { - static auto inst = std::make_shared(std::cout); - return inst; + static auto inst = std::make_shared(std::cout); + return inst; } inline std::shared_ptr& stderr_sink () { - static auto inst = std::make_shared(std::cerr); - return inst; + static auto inst = std::make_shared(std::cerr); + return inst; }