diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 7e352fa0..918bfa3d 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -67,6 +67,9 @@ using level_t = std::atomic; using log_err_handler = std::function; +using rotating_logger_cb = std::function)>; +using daily_logger_cb = std::function; + //Log level enum namespace level { diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index 7fe9ab40..6d1059d6 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -59,25 +59,25 @@ inline std::shared_ptr spdlog::basic_logger_st(const std::string } // Create multi/single threaded rotating file logger -inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) +inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, rotating_logger_cb cb /*= nullptr*/) { - return create(logger_name, filename, max_file_size, max_files); + return create(logger_name, filename, max_file_size, max_files, cb); } -inline std::shared_ptr spdlog::rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) +inline std::shared_ptr spdlog::rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, rotating_logger_cb cb /*= nullptr*/) { - return create(logger_name, filename, max_file_size, max_files); + return create(logger_name, filename, max_file_size, max_files, cb); } // Create file logger which creates new file at midnight): -inline std::shared_ptr spdlog::daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour, int minute) +inline std::shared_ptr spdlog::daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour, int minute, daily_logger_cb cb /*= nullptr*/) { - return create(logger_name, filename, hour, minute); + return create(logger_name, filename, hour, minute, cb); } -inline std::shared_ptr spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute) +inline std::shared_ptr spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute, daily_logger_cb cb /*= nullptr*/) { - return create(logger_name, filename, hour, minute); + return create(logger_name, filename, hour, minute, cb); } diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h index 421acc8a..8bc48830 100644 --- a/include/spdlog/sinks/file_sinks.h +++ b/include/spdlog/sinks/file_sinks.h @@ -66,12 +66,13 @@ class rotating_file_sink SPDLOG_FINAL : public base_sink < Mutex > { public: rotating_file_sink(const filename_t &base_filename, - std::size_t max_size, std::size_t max_files) : + std::size_t max_size, std::size_t max_files, rotating_logger_cb cb) : _base_filename(base_filename), _max_size(max_size), _max_files(max_files), _current_size(0), - _file_helper() + _file_helper(), + _on_finish_cb(cb) { _file_helper.open(calc_filename(_base_filename, 0)); _current_size = _file_helper.size(); //expensive. called only once @@ -115,7 +116,10 @@ private: void _rotate() { using details::os::filename_to_str; + std::vector files; _file_helper.close(); + + for (auto i = _max_files; i > 0; --i) { filename_t src = calc_filename(_base_filename, i - 1); @@ -128,18 +132,31 @@ private: throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target), errno); } } - if (details::file_helper::file_exists(src) && details::os::rename(src, target)) + if (details::file_helper::file_exists(src)) { - throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); + if (details::os::rename(src, target)) + { + throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); + } + if (_on_finish_cb) + { + files.push_back(target); + } } } _file_helper.reopen(true); + + if (_on_finish_cb) + { + _on_finish_cb(files); + } } filename_t _base_filename; std::size_t _max_size; std::size_t _max_files; std::size_t _current_size; details::file_helper _file_helper; + rotating_logger_cb _on_finish_cb; }; typedef rotating_file_sink rotating_file_sink_mt; @@ -186,9 +203,11 @@ public: daily_file_sink( const filename_t& base_filename, int rotation_hour, - int rotation_minute) : _base_filename(base_filename), + int rotation_minute, + daily_logger_cb cb) : _base_filename(base_filename), _rotation_h(rotation_hour), - _rotation_m(rotation_minute) + _rotation_m(rotation_minute), + _daily_cb(cb) { if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); @@ -202,8 +221,13 @@ protected: { if (std::chrono::system_clock::now() >= _rotation_tp) { + auto old_file_name = _file_helper.filename(); _file_helper.open(FileNameCalc::calc_filename(_base_filename)); _rotation_tp = _next_rotation_tp(); + if (_daily_cb) + { + _daily_cb(old_file_name); + } } _file_helper.write(msg); } @@ -234,6 +258,7 @@ private: int _rotation_m; std::chrono::system_clock::time_point _rotation_tp; details::file_helper _file_helper; + daily_logger_cb _daily_cb; }; typedef daily_file_sink daily_file_sink_mt; diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 5da20621..c42b6a94 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -77,14 +77,14 @@ std::shared_ptr basic_logger_st(const std::string& logger_name, const fi // // Create and register multi/single threaded rotating file logger // -std::shared_ptr rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); -std::shared_ptr rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); +std::shared_ptr rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, rotating_logger_cb cb = nullptr); +std::shared_ptr rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files, rotating_logger_cb cb = nullptr); // // Create file logger which creates new file on the given time (default in midnight): // -std::shared_ptr daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0); -std::shared_ptr daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0); +std::shared_ptr daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, daily_logger_cb cb = nullptr); +std::shared_ptr daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0, daily_logger_cb cb = nullptr); // // Create and register stdout/stderr loggers diff --git a/tests/file_log.cpp b/tests/file_log.cpp index 45f6e8c1..92938704 100644 --- a/tests/file_log.cpp +++ b/tests/file_log.cpp @@ -75,6 +75,31 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]") REQUIRE(get_filesize(filename1) <= 1024); } +TEST_CASE("rotating_file_logger_cb", "[rotating_logger]]") +{ + return; + prepare_logdir(); + std::string basename = "logs/rotating_log_cb"; + std::vector file_names; + auto cb_fun = [&file_names](std::vector _file_names) mutable + { + file_names = _file_names; + }; + + auto logger = spdlog::rotating_logger_mt("logger", basename, 120, 3, cb_fun); + for (int i = 0; i < 100; ++i) + logger->info("0123456789"); + logger->flush(); + + REQUIRE(file_names.size() == 3); + + REQUIRE(get_filesize(basename) <= 120); + for (auto i = 1; i < 3; i++) + { + auto filename1 = basename + "." + std::to_string(i); + REQUIRE(get_filesize(filename1) <= 120); + } +} TEST_CASE("daily_logger", "[daily_logger]]") { @@ -108,7 +133,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger_dateonly]]") fmt::MemoryWriter w; w.write("{}_{:04d}-{:02d}-{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - auto logger = spdlog::create("logger", basename, 0, 0); + auto logger = spdlog::create("logger", basename, 0, 0, nullptr); for (int i = 0; i < 10; ++i) logger->info("Test message {}", i); logger->flush(); @@ -140,7 +165,7 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger_custom]]") fmt::MemoryWriter w; w.write("{}{:04d}{:02d}{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - auto logger = spdlog::create("logger", basename, 0, 0); + auto logger = spdlog::create("logger", basename, 0, 0, nullptr); for (int i = 0; i < 10; ++i) logger->info("Test message {}", i);