diff --git a/example/example.cpp b/example/example.cpp index 3a8a21e2..ed825cc6 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -18,7 +18,7 @@ using namespace utils; int main(int argc, char* argv[]) { - const unsigned int howmany = argc <= 1 ? 1000000:atoi(argv[1]); + const unsigned int howmany = argc <= 1 ? 4000000:atoi(argv[1]); logger cout_logger ("", sinks::stdout_sink()); cout_logger.set_min_level(c11log::level::TRACE); @@ -28,7 +28,7 @@ int main(int argc, char* argv[]) auto fsink = std::make_shared("log", "txt", 1024*1024*50 , 5, 0); auto nullsink = sinks::null_sink::get(); //auto as = std::make_shared(1000); - //as->add_sink(sinks::null_sink::get()); + //as->add_sink(fsink); logger my_logger ("my_logger", nullsink); @@ -37,6 +37,7 @@ int main(int argc, char* argv[]) for(unsigned int i = 1; i <= howmany ; ++i) my_logger.info("Hello logger: ") << 4.5 <<'\t' << i << "\tasdasd:" << 123 << 'f'; + //as->shutdown(std::chrono::milliseconds(15000)); auto delta = system_clock::now() - start; auto delta_d = duration_cast> (delta).count(); diff --git a/example/makefile b/example/makefile index 907a179a..39a9f14c 100644 --- a/example/makefile +++ b/example/makefile @@ -1,6 +1,6 @@ CXX = g++ CXXFLAGS = -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -I../include -CXX_RELEASE_FLAGS = -O3 -flto -g +CXX_RELEASE_FLAGS = -O3 -flto CXX_DEBUG_FLAGS= -g OUTBIN = example diff --git a/include/c11log/common_types.h b/include/c11log/common_types.h index dafd48e9..527996bd 100644 --- a/include/c11log/common_types.h +++ b/include/c11log/common_types.h @@ -6,7 +6,6 @@ namespace c11log { typedef std::chrono::system_clock log_clock; -typedef std::pair bufpair_t; namespace level { diff --git a/include/c11log/details/flush_helper.h b/include/c11log/details/flush_helper.h index f4827324..084f7447 100644 --- a/include/c11log/details/flush_helper.h +++ b/include/c11log/details/flush_helper.h @@ -12,10 +12,10 @@ public: explicit file_flush_helper(const std::size_t flush_every): _flush_every(flush_every), _write_counter(0) {}; - - void write(const bufpair_t& msg, std::ofstream& ofs) + + void write(const std::string& msg, std::ofstream& ofs) { - ofs.write(msg.first, msg.second); + ofs.write(msg.data(), msg.size()); if(++_write_counter == _flush_every) { ofs.flush(); diff --git a/include/c11log/details/line_logger.h b/include/c11log/details/line_logger.h index 6183c509..03d47e5c 100644 --- a/include/c11log/details/line_logger.h +++ b/include/c11log/details/line_logger.h @@ -1,8 +1,9 @@ #pragma once +#include #include "../common_types.h" #include "../logger.h" -#include "stack_oss.h" + // line_logger class. // aggregates single log line (on the stack if possibe) and calls the logger upon destruction @@ -30,7 +31,7 @@ public: _log_msg.msg_level, _log_msg.msg_time, _oss); - _log_msg.msg_header_size = _oss.size(); + _log_msg.msg_header_size = _oss.str().size(); } } @@ -43,7 +44,7 @@ public: line_logger(line_logger&& other) : _callback_logger(other._callback_logger), _log_msg(std::move(other._log_msg)), - _oss(std::move(other._oss)), + _oss(std::move(other._oss.str())), _enabled(other._enabled), _empty(other._empty) { @@ -58,7 +59,7 @@ public: if (_enabled && !_empty) { _oss << os::eol(); - _log_msg.msg_buf = _oss.buf(); + _log_msg.str = _oss.str(); _callback_logger->_log_it(_log_msg); } } @@ -90,7 +91,8 @@ public: private: logger* _callback_logger; log_msg _log_msg; - details::stack_oss _oss; + //details::stack_oss _oss; + std::ostringstream _oss; bool _enabled; bool _empty; }; diff --git a/include/c11log/details/log_msg.h b/include/c11log/details/log_msg.h index 4eb3ee87..85fda0ba 100644 --- a/include/c11log/details/log_msg.h +++ b/include/c11log/details/log_msg.h @@ -7,12 +7,53 @@ namespace details struct log_msg { log_msg() = default; - log_msg(level::level_enum l):msg_level(l) {}; - - bufpair_t msg_buf; - log_clock::time_point msg_time; + log_msg(level::level_enum l): + msg_level(l), + msg_time(), + msg_header_size(0), + str() {} + + + log_msg(const log_msg& other): + msg_level(other.msg_level), + msg_time(other.msg_time), + msg_header_size(other.msg_header_size), + str(other.str) {} + + log_msg(log_msg&& other):log_msg() + { + swap(*this, other); + } + + friend void swap(log_msg& l, log_msg& r) + { + using std::swap; + swap(l.msg_level, r.msg_level); + swap(l.msg_time, r.msg_time); + swap(l.msg_header_size, r.msg_header_size); + swap(l.str, r.str); + } + + + + log_msg& operator=(log_msg other) + { + swap(*this, other); + return *this; + } + + + void clear() + { + msg_header_size = 0; + str.clear(); + } + + level::level_enum msg_level; + log_clock::time_point msg_time; std::size_t msg_header_size; - level::level_enum msg_level; + std::string str; + }; } } diff --git a/include/c11log/details/stack_buf.h b/include/c11log/details/stack_buf.h deleted file mode 100644 index bfe9d619..00000000 --- a/include/c11log/details/stack_buf.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Fast memory storage -// stores its contents on the stack when possible, in vector otherwise -// NOTE: User should be remember that returned buffer might be on the stack!! -namespace c11log -{ -namespace details -{ - -template -class stack_buf -{ -public: - stack_buf():_v(),_stack_buf(), _stack_size(0) {} - ~stack_buf() {}; - - stack_buf& operator=(const stack_buf other) = delete; - stack_buf& operator=(stack_buf&& other) = delete; - - stack_buf(const bufpair_t& buf_to_copy):stack_buf() - { - append(buf_to_copy); - } - - stack_buf(const stack_buf& other) - { - _stack_size = other._stack_size; - if(!other._v.empty()) - _v = other._v; - else if(_stack_size) - std::copy(other._stack_buf.begin(), other._stack_buf.begin()+_stack_size, _stack_buf.begin()); - } - - stack_buf(stack_buf&& other) - { - _stack_size = other._stack_size; - if(!other._v.empty()) - _v = std::move(other._v); - else if(_stack_size) - std::copy(other._stack_buf.begin(), other._stack_buf.begin()+_stack_size, _stack_buf.begin()); - other.clear(); - } - - void append(const char* buf, std::size_t buf_size) - { - //If we are aleady using _v, forget about the stack - if(!_v.empty()) - { - _v.insert(_v.end(), buf, buf+ buf_size); - } - //Try use the stack - else - { - if(_stack_size+buf_size <= STACK_SIZE) - { - std::memcpy(&_stack_buf[_stack_size], buf, buf_size); - _stack_size+=buf_size; - } - //Not enough stack space. Copy all to _v - else - { - _v.reserve(_stack_size+buf_size); - if(_stack_size) - _v.insert(_v.end(), _stack_buf.begin(), _stack_buf.begin() +_stack_size); - _v.insert(_v.end(), buf, buf+buf_size); - } - } - } - - void append(const bufpair_t &buf) - { - append(buf.first, buf.second); - } - - void clear() - { - _stack_size = 0; - _v.clear(); - } - - bufpair_t get() const - { - if(!_v.empty()) - return bufpair_t(_v.data(), _v.size()); - else - return bufpair_t(_stack_buf.data(), _stack_size); - } - - std::size_t size() const - { - if(!_v.empty()) - return _v.size(); - else - return _stack_size; - } - -private: - std::vector _v; - std::array _stack_buf; - std::size_t _stack_size; -}; - -} -} //namespace c11log { namespace details { diff --git a/include/c11log/details/stack_oss.h b/include/c11log/details/stack_oss.h deleted file mode 100644 index ffdb07f5..00000000 --- a/include/c11log/details/stack_oss.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -// Faster than ostringstream--returns its string by ref -#include -#include "c11log/details/stack_buf.h" - -namespace c11log -{ -namespace details -{ - -class stack_devicebuf:public std::streambuf -{ -public: - using Base = std::streambuf; - stack_devicebuf() = default; - ~stack_devicebuf() = default; - - stack_devicebuf& operator=(const stack_devicebuf&) = delete; - - stack_devicebuf(const stack_devicebuf& other):std::basic_streambuf(),_stackbuf(other._stackbuf) - {} - - stack_devicebuf(stack_devicebuf&& other):std::basic_streambuf(),_stackbuf(std::move(other._stackbuf)) - { - other.clear(); - } - - bufpair_t buf() const - { - return _stackbuf.get(); - } - - std::size_t size() const - { - return _stackbuf.size(); - } - - void clear() - { - _stackbuf.clear(); - } - -protected: - // copy the give buffer into the accumulated fast buffer - std::streamsize xsputn(const char_type* s, std::streamsize count) override - { - _stackbuf.append(s, static_cast(count)); - return count; - } - - int_type overflow(int_type ch) override - { - if (traits_type::not_eof(ch)) - { - char c = traits_type::to_char_type(ch); - xsputn(&c, 1); - } - return ch; - } -private: - stack_buf<192> _stackbuf; -}; - -class stack_oss:public std::ostream -{ -public: - stack_oss():std::ostream(&_dev) {} - ~stack_oss() = default; - - stack_oss& operator=(const stack_oss& other) = delete; - stack_oss& operator=(const stack_oss&& other) = delete; - - stack_oss(const stack_oss& other):std::basic_ios(), std::ostream(&_dev), _dev(other._dev) - {} - - stack_oss(stack_oss&& other):std::basic_ios(), std::ostream(&_dev), _dev(std::move(other._dev)) - { - other.clear(); - } - - bufpair_t buf() const - { - return _dev.buf(); - } - - std::size_t size() const - { - return _dev.size(); - } - - void clear() - { - _dev.clear(); - } - -private: - stack_devicebuf _dev; -}; -} -} diff --git a/include/c11log/formatter.h b/include/c11log/formatter.h index 9f431850..7bc76395 100644 --- a/include/c11log/formatter.h +++ b/include/c11log/formatter.h @@ -7,10 +7,10 @@ #include #include #include - +#include #include "common_types.h" #include "details/os.h" -#include "details/stack_oss.h" + namespace c11log { @@ -57,8 +57,7 @@ inline void c11log::formatters::default_formatter::_format_time(const log_clock: __declspec(thread) static size_t s_cache_size; __declspec(thread) static std::time_t s_cache_time_t = 0; #else - thread_local static char s_cache_str[64]; - thread_local static size_t s_cache_size; + thread_local static std::string s_cache_timestr; thread_local static std::time_t s_cache_time_t = 0; #endif @@ -67,7 +66,7 @@ inline void c11log::formatters::default_formatter::_format_time(const log_clock: if(tp_time_t != s_cache_time_t) { auto tm_now = details::os::localtime(tp_time_t); - details::stack_oss time_oss; + std::ostringstream time_oss; time_oss.fill('0'); time_oss << '[' << tm_now.tm_year + 1900 << '-'; time_oss.width(2); @@ -82,10 +81,10 @@ inline void c11log::formatters::default_formatter::_format_time(const log_clock: time_oss << tm_now.tm_sec << ']'; //Cache the resulted string and its size s_cache_time_t = tp_time_t; - //const std::string &s = time_oss.str_ref(); - bufpair_t buf = time_oss.buf(); - std::memcpy(s_cache_str, buf.first, buf.second); - s_cache_size = buf.second; + //const std::string &s = time_oss.str_ref(); + s_cache_timestr = time_oss.str(); + + } - output.write(s_cache_str, s_cache_size); + output << s_cache_timestr; } diff --git a/include/c11log/logger.h b/include/c11log/logger.h index 765b4e5b..62e8390c 100644 --- a/include/c11log/logger.h +++ b/include/c11log/logger.h @@ -6,7 +6,7 @@ #include #include #include - +#include #include "common_types.h" #include "sinks/base_sink.h" #include "details/factory.h" @@ -27,10 +27,11 @@ class logger { public: - using sink_ptr = std::shared_ptr; - using formatter_ptr = std::shared_ptr; + using sink_ptr = std::shared_ptr; using sinks_vector_t = std::vector; - using sinks_init_list = std::initializer_list; + using sinks_init_list = std::initializer_list; + + using formatter_ptr = std::shared_ptr; logger(const std::string& name, sinks_init_list, formatter_ptr = nullptr); logger(const std::string& name, sink_ptr, formatter_ptr = nullptr); diff --git a/include/c11log/sinks/async_sink.h b/include/c11log/sinks/async_sink.h index 4bd22d38..e3553520 100644 --- a/include/c11log/sinks/async_sink.h +++ b/include/c11log/sinks/async_sink.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "base_sink.h" #include "../logger.h" @@ -18,27 +18,19 @@ namespace sinks { -static void msg_deleter(details::log_msg* msg_to_delete) -{ - delete []msg_to_delete->msg_buf.first; - delete msg_to_delete; -} - class async_sink : public base_sink { public: + using q_type = details::blocking_queue; - - using queue_type = details::blocking_queue>>; - - explicit async_sink(const queue_type::size_type max_queue_size); + explicit async_sink(const q_type::size_type max_queue_size); //Stop logging and join the back thread // TODO: limit with timeout of the join and kill it afterwards? ~async_sink(); void add_sink(logger::sink_ptr sink); void remove_sink(logger::sink_ptr sink_ptr); - queue_type& q(); + q_type& q(); //Wait to remaining items (if any) in the queue to be written and shutdown void shutdown(const std::chrono::milliseconds& timeout); @@ -50,7 +42,7 @@ protected: private: c11log::logger::sinks_vector_t _sinks; std::atomic _active; - queue_type _q; + q_type _q; std::thread _back_thread; //Clear all remaining messages(if any), stop the _back_thread and join it void _shutdown(); @@ -63,7 +55,7 @@ private: // async_sink class implementation /////////////////////////////////////////////////////////////////////////////// -inline c11log::sinks::async_sink::async_sink(const queue_type::size_type max_queue_size) +inline c11log::sinks::async_sink::async_sink(const q_type::size_type max_queue_size) :_sinks(), _active(true), _q(max_queue_size), @@ -77,19 +69,10 @@ inline c11log::sinks::async_sink::~async_sink() inline void c11log::sinks::async_sink::_sink_it(const details::log_msg& msg) -{ - auto msg_size = msg.msg_buf.second; - if(!_active || !msg_size) +{ + if(!_active || msg.str.empty()) return; - //re allocate on the heap the (stack based) message - details::log_msg* new_msg = new details::log_msg(msg); - - char *buf = new char[msg_size]; - std::memcpy(buf, msg.msg_buf.first, msg_size); - new_msg->msg_buf = bufpair_t(buf, msg_size); - // Create unique_ptr with custom deleter and push it - queue_type::item_type new_shared_msg(new_msg, msg_deleter); - _q.push(std::move(new_shared_msg)); + _q.push(msg); } inline void c11log::sinks::async_sink::_thread_loop() @@ -97,12 +80,12 @@ inline void c11log::sinks::async_sink::_thread_loop() static std::chrono::seconds pop_timeout { 1 }; while (_active) { - queue_type::item_type msg; + q_type::item_type msg; if (_q.pop(msg, pop_timeout)) { for (auto &sink : _sinks) { - sink->log(*msg); + sink->log(msg); if(!_active) break; } @@ -115,12 +98,12 @@ 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 sink_ptr) +inline void c11log::sinks::async_sink::remove_sink(logger::sink_ptr sink) { - _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink_ptr), _sinks.end()); + _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end()); } -inline c11log::sinks::async_sink::queue_type& c11log::sinks::async_sink::q() +inline c11log::sinks::async_sink::q_type& c11log::sinks::async_sink::q() { return _q; } diff --git a/include/c11log/sinks/console_sinks.h b/include/c11log/sinks/console_sinks.h index 4d28268b..6adb9759 100644 --- a/include/c11log/sinks/console_sinks.h +++ b/include/c11log/sinks/console_sinks.h @@ -23,7 +23,7 @@ protected: virtual void _sink_it(const details::log_msg& msg) override { std::lock_guard lock(_mutex); - _ostream.write(msg.msg_buf.first, msg.msg_buf.second); + _ostream << msg.str; } std::ostream& _ostream; diff --git a/include/c11log/sinks/file_sinks.h b/include/c11log/sinks/file_sinks.h index 0b345321..a82f841d 100644 --- a/include/c11log/sinks/file_sinks.h +++ b/include/c11log/sinks/file_sinks.h @@ -31,7 +31,7 @@ protected: void _sink_it(const details::log_msg& msg) override { std::lock_guard lock(_mutex); - _flush_helper.write(msg.msg_buf, _ofstream); + _flush_helper.write(msg.str, _ofstream); } private: std::mutex _mutex; @@ -65,13 +65,13 @@ protected: { std::lock_guard lock(_mutex); - _current_size += msg.msg_buf.second; + _current_size += msg.str.size(); if (_current_size > _max_size) { _rotate(); - _current_size = msg.msg_buf.second; + _current_size = msg.str.size(); } - _flush_helper.write(msg.msg_buf, _ofstream); + _flush_helper.write(msg.str, _ofstream); } @@ -144,7 +144,7 @@ protected: _ofstream.open(_calc_filename(_base_filename, _extension)); _midnight_tp = _calc_midnight_tp(); } - _flush_helper.write(msg.msg_buf, _ofstream); + _flush_helper.write(msg.str, _ofstream); } private: