From 9c04504881722a7b62e4c8024676cb785c3b8600 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Fri, 16 Sep 2016 02:58:02 +0300 Subject: [PATCH 1/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 435ce5d2..e023c56b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Just copy the source [folder](https://github.com/gabime/spdlog/tree/master/inclu * Windows (visual studio 2013+, cygwin/mingw with g++ 4.9.1+) * Mac OSX (clang 3.5+) * Solaris (gcc 5.2.0+) + * Android ##Features * Very fast - performance is the primary goal (see [benchmarks](#benchmarks) below). From b0f823078320686972eecc94c151dd88b52b7724 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 18 Sep 2016 00:14:56 +0300 Subject: [PATCH 2/8] Fixed bug in basic_logger creating (passed truncate to force_flush arg) --- include/spdlog/details/spdlog_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index bc283c83..95aeeb07 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -39,12 +39,12 @@ inline void spdlog::drop(const std::string &name) // Create multi/single threaded simple file logger inline std::shared_ptr spdlog::basic_logger_mt(const std::string& logger_name, const filename_t& filename, bool truncate) { - return create(logger_name, filename, truncate); + return create(logger_name, filename, false, truncate); } inline std::shared_ptr spdlog::basic_logger_st(const std::string& logger_name, const filename_t& filename, bool truncate) { - return create(logger_name, filename, truncate); + return create(logger_name, filename, false, truncate); } // Create multi/single threaded rotating file logger From e97621d61d211c256c915b9f85caca5aa43d7305 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 18 Sep 2016 00:43:42 +0300 Subject: [PATCH 3/8] Removed force_flush arg from everywhere. Use flush_on(level) instead --- include/spdlog/details/file_helper.h | 13 +++------ include/spdlog/details/spdlog_impl.h | 4 +-- include/spdlog/sinks/file_sinks.h | 40 ++++++++++++---------------- tests/errors.cpp | 1 + tests/file_helper.cpp | 11 ++++---- tests/file_log.cpp | 35 +++++++++++++++++------- 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 37f1cf27..2e6ce9d2 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -31,9 +31,8 @@ public: const int open_tries = 5; const int open_interval = 10; - explicit file_helper(bool force_flush) : - _fd(nullptr), - _force_flush(force_flush) + explicit file_helper() : + _fd(nullptr) {} file_helper(const file_helper&) = delete; @@ -90,10 +89,7 @@ public: size_t msg_size = msg.formatted.size(); auto data = msg.formatted.data(); if (std::fwrite(data, 1, msg_size, _fd) != msg_size) - throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno); - - if (_force_flush) - std::fflush(_fd); + throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno); } size_t size() @@ -116,8 +112,7 @@ public: private: FILE* _fd; - filename_t _filename; - bool _force_flush; + filename_t _filename; }; } } diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index 95aeeb07..bc283c83 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -39,12 +39,12 @@ inline void spdlog::drop(const std::string &name) // Create multi/single threaded simple file logger inline std::shared_ptr spdlog::basic_logger_mt(const std::string& logger_name, const filename_t& filename, bool truncate) { - return create(logger_name, filename, false, truncate); + return create(logger_name, filename, truncate); } inline std::shared_ptr spdlog::basic_logger_st(const std::string& logger_name, const filename_t& filename, bool truncate) { - return create(logger_name, filename, false, truncate); + return create(logger_name, filename, truncate); } // Create multi/single threaded rotating file logger diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h index ff767593..fad21fe1 100644 --- a/include/spdlog/sinks/file_sinks.h +++ b/include/spdlog/sinks/file_sinks.h @@ -23,16 +23,13 @@ namespace spdlog namespace sinks { /* -* Trivial file sink with single file as target -*/ + * Trivial file sink with single file as target + */ template class simple_file_sink : public base_sink < Mutex > { public: - explicit simple_file_sink(const filename_t &filename, - bool force_flush = false, - bool truncate = false) : - _file_helper(force_flush) + explicit simple_file_sink(const filename_t &filename, bool truncate = false) { _file_helper.open(filename, truncate); } @@ -54,21 +51,20 @@ typedef simple_file_sink simple_file_sink_mt; typedef simple_file_sink simple_file_sink_st; /* -* Rotating file sink based on size -*/ + * Rotating file sink based on size + */ template class rotating_file_sink : public base_sink < Mutex > { public: rotating_file_sink(const filename_t &base_filename, const filename_t &extension, - std::size_t max_size, std::size_t max_files, - bool force_flush = false) : + std::size_t max_size, std::size_t max_files ) : _base_filename(base_filename), _extension(extension), _max_size(max_size), _max_files(max_files), _current_size(0), - _file_helper(force_flush) + _file_helper() { _file_helper.open(calc_filename(_base_filename, 0, _extension)); _current_size = _file_helper.size(); //expensive. called only once @@ -143,11 +139,11 @@ typedef rotating_file_sink rotating_file_sink_mt; typedef rotating_file_sinkrotating_file_sink_st; /* -* Default generator of daily log file names. -*/ + * Default generator of daily log file names. + */ struct default_daily_file_name_calculator { - //Create filename for the form basename.YYYY-MM-DD_hh-mm.extension + // Create filename for the form basename.YYYY-MM-DD_hh-mm.extension static filename_t calc_filename(const filename_t& basename, const filename_t& extension) { std::tm tm = spdlog::details::os::localtime(); @@ -158,11 +154,11 @@ struct default_daily_file_name_calculator }; /* -* Generator of daily log file names in format basename.YYYY-MM-DD.extension -*/ + * Generator of daily log file names in format basename.YYYY-MM-DD.extension + */ struct dateonly_daily_file_name_calculator { - //Create filename for the form basename.YYYY-MM-DD.extension + // Create filename for the form basename.YYYY-MM-DD.extension static filename_t calc_filename(const filename_t& basename, const filename_t& extension) { std::tm tm = spdlog::details::os::localtime(); @@ -173,8 +169,8 @@ struct dateonly_daily_file_name_calculator }; /* -* Rotating file sink based on date. rotates at midnight -*/ + * Rotating file sink based on date. rotates at midnight + */ template class daily_file_sink :public base_sink < Mutex > { @@ -184,12 +180,10 @@ public: const filename_t& base_filename, const filename_t& extension, int rotation_hour, - int rotation_minute, - bool force_flush = false) : _base_filename(base_filename), + int rotation_minute) : _base_filename(base_filename), _extension(extension), _rotation_h(rotation_hour), - _rotation_m(rotation_minute), - _file_helper(force_flush) + _rotation_m(rotation_minute) { if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); diff --git a/tests/errors.cpp b/tests/errors.cpp index 6cb4265e..04cd97c2 100644 --- a/tests/errors.cpp +++ b/tests/errors.cpp @@ -28,6 +28,7 @@ TEST_CASE("custom_error_handler", "[errors]]") prepare_logdir(); std::string filename = "logs/simple_log.txt"; auto logger = spdlog::create("logger", filename, true); + logger->flush_on(spdlog::level::info); logger->set_error_handler([=](const std::string& msg) { throw custom_ex(); diff --git a/tests/file_helper.cpp b/tests/file_helper.cpp index 54d54cf1..599c233f 100644 --- a/tests/file_helper.cpp +++ b/tests/file_helper.cpp @@ -12,6 +12,7 @@ static void write_with_helper(file_helper &helper, size_t howmany) log_msg msg; msg.formatted << std::string(howmany, '1'); helper.write(msg); + helper.flush(); } @@ -19,7 +20,7 @@ TEST_CASE("file_helper_filename", "[file_helper::filename()]]") { prepare_logdir(); - file_helper helper(false); + file_helper helper; helper.open(target_filename); REQUIRE(helper.filename() == target_filename); } @@ -31,7 +32,7 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]") prepare_logdir(); size_t expected_size = 123; { - file_helper helper(true); + file_helper helper; helper.open(target_filename); write_with_helper(helper, expected_size); REQUIRE(static_cast(helper.size()) == expected_size); @@ -44,7 +45,7 @@ TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]") { prepare_logdir(); REQUIRE(!file_helper::file_exists(target_filename)); - file_helper helper(false); + file_helper helper; helper.open(target_filename); REQUIRE(file_helper::file_exists(target_filename)); } @@ -52,7 +53,7 @@ TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]") TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]") { prepare_logdir(); - file_helper helper(true); + file_helper helper; helper.open(target_filename); write_with_helper(helper, 12); REQUIRE(helper.size() == 12); @@ -64,7 +65,7 @@ TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]") { prepare_logdir(); size_t expected_size = 14; - file_helper helper(true); + file_helper helper; helper.open(target_filename); write_with_helper(helper, expected_size); REQUIRE(helper.size() == expected_size); diff --git a/tests/file_log.cpp b/tests/file_log.cpp index bc5da728..ab1d9432 100644 --- a/tests/file_log.cpp +++ b/tests/file_log.cpp @@ -18,7 +18,26 @@ TEST_CASE("simple_file_logger", "[simple_logger]]") logger->flush(); REQUIRE(file_contents(filename) == std::string("Test message 1\nTest message 2\n")); REQUIRE(count_lines(filename) == 2); +} + +TEST_CASE("flush_on", "[flush_on]]") +{ + prepare_logdir(); + std::string filename = "logs/simple_log.txt"; + + auto logger = spdlog::create("logger", filename); + logger->set_pattern("%v"); + logger->set_level(spdlog::level::trace); + logger->flush_on(spdlog::level::info); + logger->trace("Should not be flushed"); + REQUIRE(count_lines(filename) == 0); + + logger->info("Test message {}", 1); + logger->info("Test message {}", 2); + logger->flush(); + REQUIRE(file_contents(filename) == std::string("Should not be flushed\nTest message 1\nTest message 2\n")); + REQUIRE(count_lines(filename) == 3); } TEST_CASE("rotating_file_logger1", "[rotating_logger]]") @@ -26,15 +45,13 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]") prepare_logdir(); std::string basename = "logs/rotating_log"; auto logger = spdlog::rotating_logger_mt("logger", basename, 1024, 0); - logger->flush_on(spdlog::level::info); + for (int i = 0; i < 10; ++i) logger->info("Test message {}", i); + logger->flush(); auto filename = basename + ".txt"; REQUIRE(count_lines(filename) == 10); - for (int i = 0; i < 1000; i++) - logger->info("Test message {}", i); - } @@ -61,7 +78,6 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]") TEST_CASE("daily_logger", "[daily_logger]]") { - prepare_logdir(); //calculate filename (time based) std::string basename = "logs/daily_log"; @@ -92,10 +108,10 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger_dateonly]]") fmt::MemoryWriter w; w.write("{}_{:04d}-{:02d}-{:02d}.txt", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - auto logger = spdlog::create("logger", basename, "txt", 0, 0, true); + auto logger = spdlog::create("logger", basename, "txt", 0, 0); for (int i = 0; i < 10; ++i) logger->info("Test message {}", i); - + logger->flush(); auto filename = w.str(); REQUIRE(count_lines(filename) == 10); } @@ -124,11 +140,12 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger_custom]]") fmt::MemoryWriter w; w.write("{}{:04d}{:02d}{:02d}.txt", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - auto logger = spdlog::create("logger", basename, "txt", 0, 0, true); + auto logger = spdlog::create("logger", basename, "txt", 0, 0); for (int i = 0; i < 10; ++i) logger->info("Test message {}", i); - auto filename = w.str(); + logger->flush(); + auto filename = w.str(); REQUIRE(count_lines(filename) == 10); } From 214c67788f99c63ab4081b350eee81a7b54bb528 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 18 Sep 2016 01:51:53 +0300 Subject: [PATCH 4/8] add async with null sink bench --- bench/Makefile | 7 ++- bench/spdlog-null-async.cpp | 112 ++++++++++++++++++++++++++++++++++++ bench/utils.h | 35 +++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 bench/spdlog-null-async.cpp create mode 100644 bench/utils.h diff --git a/bench/Makefile b/bench/Makefile index ea2220b9..fa787d18 100644 --- a/bench/Makefile +++ b/bench/Makefile @@ -3,7 +3,7 @@ CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG -binaries=spdlog-bench spdlog-bench-mt spdlog-async boost-bench boost-bench-mt glog-bench glog-bench-mt g2log-async easylogging-bench easylogging-bench-mt +binaries=spdlog-bench spdlog-bench-mt spdlog-async spdlog-null-async boost-bench boost-bench-mt glog-bench glog-bench-mt g2log-async easylogging-bench easylogging-bench-mt all: $(binaries) @@ -17,6 +17,11 @@ spdlog-async: spdlog-async.cpp $(CXX) spdlog-async.cpp -o spdlog-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS) +spdlog-null-async: spdlog-null-async.cpp + $(CXX) spdlog-null-async.cpp -o spdlog-null-async $(CXXFLAGS) $(CXX_RELEASE_FLAGS) + + + BOOST_FLAGS = -DBOOST_LOG_DYN_LINK -I/usr/include -lboost_log -lboost_log_setup -lboost_filesystem -lboost_system -lboost_thread -lboost_regex -lboost_date_time -lboost_chrono boost-bench: boost-bench.cpp diff --git a/bench/spdlog-null-async.cpp b/bench/spdlog-null-async.cpp new file mode 100644 index 00000000..435d7eb5 --- /dev/null +++ b/bench/spdlog-null-async.cpp @@ -0,0 +1,112 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +// +// bench.cpp : spdlog benchmarks +// +#include +#include // EXIT_FAILURE +#include +#include +#include +#include +#include "spdlog/spdlog.h" +#include "spdlog/async_logger.h" +#include "spdlog/sinks/null_sink.h" +#include "utils.h" + + +using namespace std; +using namespace std::chrono; +using namespace spdlog; +using namespace spdlog::sinks; +using namespace utils; + + + +size_t bench_as(int howmany, std::shared_ptr log, int thread_count); + +int main(int argc, char* argv[]) +{ + + int queue_size = 1048576; + int howmany = 1000000; + int threads = 10; + int iters = 10; + + try + { + + if(argc > 1) + howmany = atoi(argv[1]); + if (argc > 2) + threads = atoi(argv[2]); + if (argc > 3) + queue_size = atoi(argv[3]); + + + cout << "\n*******************************************************************************\n"; + cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " messages " << endl; + cout << "*******************************************************************************\n"; + + spdlog::set_async_mode(queue_size); + + size_t total_rate = 0; + + for(int i = 0; i < iters; ++i) + { + //auto as = spdlog::daily_logger_st("as", "logs/daily_async"); + auto as = spdlog::create("async(null-sink)"); + total_rate+= bench_as(howmany, as, threads); + spdlog::drop("async(null-sink)"); + } + std::cout << endl; + std::cout << "Avg rate: " << format(total_rate/iters) << "/sec" < log, int thread_count) +{ + cout << log->name() << "...\t\t" << flush; + std::atomic msg_counter {0}; + vector threads; + auto start = system_clock::now(); + for (int t = 0; t < thread_count; ++t) + { + threads.push_back(std::thread([&]() + { + for(;;) + { + int counter = ++msg_counter; + if (counter > howmany) break; + log->info("Hello logger: msg number {}", counter); + } + })); + } + + + for(auto &t:threads) + { + t.join(); + }; + + + auto delta = system_clock::now() - start; + auto delta_d = duration_cast> (delta).count(); + auto per_sec = size_t(howmany / delta_d); + cout << format(per_sec) << "/sec" << endl; + return per_sec; +} diff --git a/bench/utils.h b/bench/utils.h new file mode 100644 index 00000000..b260f724 --- /dev/null +++ b/bench/utils.h @@ -0,0 +1,35 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include +#include +#include + +namespace utils +{ + +template +inline std::string format(const T& value) +{ + static std::locale loc(""); + std::stringstream ss; + ss.imbue(loc); + ss << value; + return ss.str(); +} + +template<> +inline std::string format(const double & value) +{ + static std::locale loc(""); + std::stringstream ss; + ss.imbue(loc); + ss << std::fixed << std::setprecision(1) << value; + return ss.str(); +} + +} From 1f1f6a5f3b424203a429e9cb78e6548037adefa8 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 18 Sep 2016 02:28:41 +0300 Subject: [PATCH 5/8] Support bench under OSX --- bench/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/Makefile b/bench/Makefile index fa787d18..418a5285 100644 --- a/bench/Makefile +++ b/bench/Makefile @@ -1,5 +1,5 @@ CXX ?= g++ -CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include +CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -I../include CXX_RELEASE_FLAGS = -O3 -flto -DNDEBUG From 811eeef7a6f90535cf31c3bb2a1ca8cf9f7546be Mon Sep 17 00:00:00 2001 From: amir zamani Date: Tue, 20 Sep 2016 14:13:15 +0430 Subject: [PATCH 6/8] update os.h to fix filesize() on older win32 _fstat() always fails under older 32bit WinXP/Win2003 targets. _filelength() just works for both WinXP SDK and later Win7+ 32bit targets. --- include/spdlog/details/os.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index ed4f45cd..6d27bc39 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -31,6 +31,7 @@ #endif #include +#include #elif __linux__ @@ -204,9 +205,9 @@ inline size_t filesize(FILE *f) return st.st_size; #else //windows 32 bits - struct _stat st; - if (_fstat(fd, &st) == 0) - return st.st_size; + long ret = _filelength(fd); + if (ret >= 0) + return static_cast(ret); #endif #else // unix From 66b08294cad7cf06e5972dcf2b3a980377ea2698 Mon Sep 17 00:00:00 2001 From: Therenall Date: Sat, 24 Sep 2016 15:14:05 -0400 Subject: [PATCH 7/8] Exposed logger sinks. --- include/spdlog/details/logger_impl.h | 5 +++++ include/spdlog/logger.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index a337b359..2b27f105 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -291,3 +291,8 @@ 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 const std::vector& spdlog::logger::sinks() const +{ + return _sinks; +} diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index e998999e..ca0b4b2d 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -68,6 +68,8 @@ public: virtual void flush(); + const std::vector& sinks() const; + protected: virtual void _sink_it(details::log_msg&); virtual void _set_pattern(const std::string&); @@ -90,5 +92,3 @@ protected: } #include - - From faa184ce24d0924a6f745201e838b609a6aa2abe Mon Sep 17 00:00:00 2001 From: gabime Date: Thu, 29 Sep 2016 23:49:03 +0300 Subject: [PATCH 8/8] Added #ifdef __ANDROID__ to spllog_impl.h --- include/spdlog/details/spdlog_impl.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index bc283c83..820e03a4 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -12,9 +12,14 @@ #include #include #include +#ifdef SPDLOG_ENABLE_SYSLOG #include +#endif #include + +#ifdef __ANDROID__ #include +#endif #include #include @@ -105,7 +110,7 @@ inline std::shared_ptr spdlog::syslog_logger(const std::string& } #endif -#if defined(__ANDROID__) +#ifdef __ANDROID__ inline std::shared_ptr spdlog::android_logger(const std::string& logger_name, const std::string& tag) { return create(logger_name, tag);