diff --git a/c11logtest/c11logtest/c11logtest.vcxproj b/c11logtest/c11logtest/c11logtest.vcxproj index 3c046302..0c290ae8 100644 --- a/c11logtest/c11logtest/c11logtest.vcxproj +++ b/c11logtest/c11logtest/c11logtest.vcxproj @@ -88,8 +88,8 @@ - + diff --git a/c11logtest/c11logtest/c11logtest.vcxproj.filters b/c11logtest/c11logtest/c11logtest.vcxproj.filters index 4794c326..9edef0a7 100644 --- a/c11logtest/c11logtest/c11logtest.vcxproj.filters +++ b/c11logtest/c11logtest/c11logtest.vcxproj.filters @@ -45,9 +45,6 @@ Header Files\c11log\details - - Header Files\c11log\details - Header Files\c11log\details @@ -99,6 +96,9 @@ Header Files\c11log\details + + Header Files\c11log\details + diff --git a/example/bench.cpp b/example/bench.cpp index 44af771e..b0c401bd 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -15,29 +15,37 @@ using namespace utils; int main(int argc, char* argv[]) { - const unsigned int howmany = argc <= 1 ? 600000 : atoi(argv[1]); + try { + const unsigned int howmany = argc <= 1 ? 500000 : atoi(argv[1]); - //c11log::set_format("%t"); - auto console = c11log::create("reporter"); - //console->set_format("[%n %l] %t"); - console->set_level(c11log::level::INFO); - console->info("Starting bench with", howmany, "iterations.."); + //c11log::set_format("%t"); + auto console = c11log::create("reporter"); + //console->set_format("[%n %l] %t"); + console->set_level(c11log::level::INFO); + console->info("Starting bench with", howmany, "iterations.."); + + //auto bench = c11log::create("bench", "myrotating", "txt", 1024 * 1024 * 5, 3, 0); + auto bench = c11log::create("bench", "sdfsfddaily", "txt", 0); + //auto bench = c11log::create("bench", "simplelog.txt", 1); + //auto bench = c11log::create("bench"); + auto start = system_clock::now(); + for (unsigned int i = 1; i <= howmany; ++i) + { + c11log::get("bench")->info("Hello logger: msg number", i); + } + + auto delta = system_clock::now() - start; + auto delta_d = duration_cast> (delta).count(); + + console->info("Total:") << format(howmany); + console->info("Delta:") << format(delta_d); + console->info("Rate:") << format(howmany / delta_d) << "/sec"; - //auto bench = c11log::create("bench", "myrotating", "txt", 1024 * 1024 * 5, 3, 100); - auto bench = c11log::create("bench"); - auto start = system_clock::now(); - for (unsigned int i = 1; i <= howmany; ++i) - { - c11log::get("bench")->info("Hello logger: msg number", i); } - - auto delta = system_clock::now() - start; - auto delta_d = duration_cast> (delta).count(); - - console->info("Total:") << format(howmany); - console->info("Delta:") << format(delta_d); - console->info("Rate:") << format(howmany / delta_d) << "/sec"; - + catch (std::exception &ex) + { + std::cerr << "Exception: " << ex.what() << std::endl; + } return 0; } diff --git a/example/example.cpp b/example/example.cpp index 6d9d00d3..c9b0ae50 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -16,7 +16,7 @@ details::fast_oss f(const std::string& what) oss << what; return oss; } -int main(int, char* []) +int main_(int, char* []) { auto foss = f("test2"); diff --git a/include/c11log/common.h b/include/c11log/common.h index 32666ca1..3bf48d0d 100644 --- a/include/c11log/common.h +++ b/include/c11log/common.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include namespace c11log @@ -37,4 +36,20 @@ inline const char* to_str(c11log::level::level_enum l) return level_names[l]; } } //level + +// +// Log exception +// +class fflog_exception : public std::exception +{ +public: + fflog_exception(const std::string& msg) :_msg(msg) {}; + const char* what() const throw() override { + return _msg.c_str(); + } +private: + std::string _msg; + +}; + } //c11log diff --git a/include/c11log/details/file_helper.h b/include/c11log/details/file_helper.h new file mode 100644 index 00000000..692fc91a --- /dev/null +++ b/include/c11log/details/file_helper.h @@ -0,0 +1,90 @@ +#pragma once + + + +// Helper class for file sink +// When failing to open a file, retry several times(5) with small delay between the tries(10 ms) +// Flush to file every X writes (or never if X==0) +// Throw fflog_ exception on errors + + +#include +#include +#include +#include +#include "../common.h" + + + +namespace c11log +{ +namespace details +{ + +class file_helper +{ +public: + static const int open_max_tries = 5; + static const int sleep_ms_bewteen_tries = 10; + + explicit file_helper(const std::size_t flush_inverval): + _fd(nullptr), + _flush_inverval(flush_inverval), + _flush_countdown(flush_inverval) {}; + + file_helper(const file_helper&) = delete; + + ~file_helper() + { + if (_fd) + std::fclose(_fd); + } + + + void open(const std::string& filename) + { + + if (_fd) + std::fclose(_fd); + + _filename = filename; + for (int tries = 0; tries < open_max_tries; ++tries) + { + if(!os::fopen_s(&_fd, filename, "wb")) + return; + + std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms_bewteen_tries)); + } + + throw fflog_exception("Failed opening file " + filename + " for writing"); + } + + void close() + { + std::fclose(_fd); + } + + void write(const log_msg& msg) + { + auto& buf = msg.formatted.buf(); + size_t size = buf.size(); + if(std::fwrite(buf.data(), sizeof(char), size, _fd) != size) + throw fflog_exception("Failed writing to file " + _filename); + + if(--_flush_countdown == 0) + { + std::fflush(_fd); + _flush_countdown = _flush_inverval; + } + } + +private: + FILE* _fd; + std::string _filename; + const std::size_t _flush_inverval; + std::size_t _flush_countdown; + +}; +} +} + diff --git a/include/c11log/details/flush_helper.h b/include/c11log/details/flush_helper.h deleted file mode 100644 index 5285ec6c..00000000 --- a/include/c11log/details/flush_helper.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -// Flush to file every X writes.. -// If X is zero than never flush.. - -namespace c11log -{ -namespace details -{ - -class file_flush_helper -{ -public: - explicit file_flush_helper(const std::size_t flush_every): - _flush_every(flush_every), - _flush_countdown(flush_every) {}; - - file_flush_helper(const file_flush_helper&) = delete; - - void write(const log_msg& msg, std::ofstream& ofs) - { - auto& buf = msg.formatted.buf(); - ofs.write(buf.data(), buf.size()); - if(--_flush_countdown == 0) - { - ofs.flush(); - _flush_countdown = _flush_every; - } - } - -private: - const std::size_t _flush_every; - std::size_t _flush_countdown; -}; -} -} - diff --git a/include/c11log/details/os.h b/include/c11log/details/os.h index 512adf54..5bf38faa 100644 --- a/include/c11log/details/os.h +++ b/include/c11log/details/os.h @@ -96,11 +96,13 @@ constexpr inline unsigned short eol_size() inline bool fopen_s(FILE** fp, const std::string& filename, const char* mode) { #ifdef _WIN32 - return fopen_s(fp, filename, mode); + return ::fopen_s(fp, filename.c_str(), mode); #else *fp = fopen((filename.c_str()), mode); - return fp == nullptr; + return *fp == nullptr; #endif + + } //Return utc offset in minutes or -1 on failure diff --git a/include/c11log/logger.h b/include/c11log/logger.h index 3e4ab370..9e4d0db7 100644 --- a/include/c11log/logger.h +++ b/include/c11log/logger.h @@ -66,17 +66,6 @@ private: void _log_msg(details::log_msg& msg); }; -class fflog_exception : public std::exception -{ -public: - fflog_exception(const std::string& msg) :_msg(msg) {}; - const char* what() const throw() override { - return _msg.c_str(); - } -private: - std::string _msg; - -}; // // Registry functions for easy loggers creation and retrieval diff --git a/include/c11log/sinks/file_sinks.h b/include/c11log/sinks/file_sinks.h index c4c57225..a5c3b6c5 100644 --- a/include/c11log/sinks/file_sinks.h +++ b/include/c11log/sinks/file_sinks.h @@ -1,13 +1,11 @@ #pragma once -#include #include -#include -#include "./base_sink.h" #include +#include "./base_sink.h" + #include "../details/null_mutex.h" -#include "../details/flush_helper.h" -#include "../details/blocking_queue.h" +#include "../details/file_helper.h" @@ -24,19 +22,18 @@ class simple_file_sink : public base_sink { public: explicit simple_file_sink(const std::string &filename, - const std::size_t flush_every=0): - _ofstream(filename, std::ofstream::binary|std::ofstream::app), - _flush_helper(flush_every) + const std::size_t flush_inverval=0): + _file_helper(flush_inverval) { + _file_helper.open(filename); } protected: void _sink_it(const details::log_msg& msg) override { - _flush_helper.write(msg, _ofstream); + _file_helper.write(msg); } private: - std::ofstream _ofstream; - details::file_flush_helper _flush_helper; + details::file_helper _file_helper; }; typedef simple_file_sink simple_file_sink_mt; @@ -51,15 +48,15 @@ class rotating_file_sink : public base_sink public: rotating_file_sink(const std::string &base_filename, const std::string &extension, const std::size_t max_size, const std::size_t max_files, - const std::size_t flush_every=0): + const std::size_t flush_inverval=0): _base_filename(base_filename), _extension(extension), _max_size(max_size), _max_files(max_files), _current_size(0), - _ofstream(_calc_filename(_base_filename, 0, _extension), std::ofstream::binary), - _flush_helper(flush_every) + _file_helper(flush_inverval) { + _file_helper.open(_calc_filename(_base_filename, 0, _extension)); } protected: @@ -71,7 +68,7 @@ protected: _rotate(); _current_size = msg.formatted.size(); } - _flush_helper.write(msg, _ofstream); + _file_helper.write(msg); } @@ -95,25 +92,24 @@ private: void _rotate() { - _ofstream.close(); + _file_helper.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); + std::string src = _calc_filename(_base_filename, i - 1, _extension); + std::string 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::ofstream::binary); + _file_helper.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::ofstream _ofstream; - details::file_flush_helper _flush_helper; + details::file_helper _file_helper; }; typedef rotating_file_sink rotating_file_sink_mt; @@ -128,13 +124,13 @@ class daily_file_sink:public base_sink public: explicit daily_file_sink(const std::string& base_filename, const std::string& extension, - const std::size_t flush_every=0): + const std::size_t flush_inverval=0): _base_filename(base_filename), _extension(extension), _midnight_tp (_calc_midnight_tp() ), - _ofstream(_calc_filename(_base_filename, _extension), std::ofstream::binary|std::ofstream::app), - _flush_helper(flush_every) + _file_helper(flush_inverval) { + _file_helper.open(_calc_filename(_base_filename, _extension)); } protected: @@ -142,11 +138,11 @@ protected: { if (std::chrono::system_clock::now() >= _midnight_tp) { - _ofstream.close(); - _ofstream.open(_calc_filename(_base_filename, _extension)); + _file_helper.close(); + _file_helper.open(_calc_filename(_base_filename, _extension)); _midnight_tp = _calc_midnight_tp(); } - _flush_helper.write(msg, _ofstream); + _file_helper.write(msg); } private: @@ -176,8 +172,7 @@ private: std::string _base_filename; std::string _extension; std::chrono::system_clock::time_point _midnight_tp; - std::ofstream _ofstream; - details::file_flush_helper _flush_helper; + details::file_helper _file_helper; };