From 5306b1fd58b84a8b8471c1e0efb6750614a66002 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Thu, 4 May 2023 14:20:11 +0530 Subject: [PATCH 01/10] minute_file_sink to support every 1 min file rotation example driver code: auto logger = spdlog::minute_logger_mt("minutes_basic_logger", "logs/min-log.txt",false,60); --- include/spdlog/sinks/minute_file_sink.h | 208 ++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 include/spdlog/sinks/minute_file_sink.h diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h new file mode 100644 index 000000000..26be135d7 --- /dev/null +++ b/include/spdlog/sinks/minute_file_sink.h @@ -0,0 +1,208 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +//File: minute_file_sink to support every 1 min file rotation. +//Author Manoj Mallawaarachchie manoj_ws@yahoo.com / manoj@vizuamatix.com +//example driver code: +//auto logger = spdlog::minute_logger_mt("minutes_basic_logger", "logs/min-log.txt",false,60); + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * Generator of Minute log file names in format basename.YYYY-MM-DD-HH-MM.ext + */ +struct minute_filename_calculator +{ + // Create filename for the form basename.YYYY-MM-DD-H-M + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour,now_tm.tm_min,ext);//colock details define in os-inl.h + } +}; + +/* + * Rotating file sink based on time(minutes). + * If truncate != false , the created file will be truncated. + * If max_files > 0, retain only the last max_files and delete previous. + */ +template +class minute_file_sink final : public base_sink +{ +public: + // create hourly file sink which rotates on given time + minute_file_sink( + filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) + : base_filename_(std::move(base_filename)) + , file_helper_{event_handlers} + , truncate_(truncate) + , max_files_(max_files) + , filenames_q_() + { + auto now = log_clock::now(); + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + file_helper_.open(filename, truncate_); + remove_init_file_ = file_helper_.size() == 0; + rotation_tp_ = next_rotation_tp_(); + + if (max_files_ > 0) + { + init_filenames_q_(); + } + } + + filename_t filename() + { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + auto time = msg.time; + bool should_rotate = time >= rotation_tp_; + if (should_rotate) + { + if (remove_init_file_) + { + file_helper_.close(); + details::os::remove(file_helper_.filename()); + } + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + } + remove_init_file_ = false; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + + // Do the cleaning only at the end because it might throw on failure. + if (should_rotate && max_files_ > 0) + { + delete_old_(); + } + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + void init_filenames_q_() + { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) + { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) + { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::minutes(1); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) + { + filenames_q_.push_back(std::move(*iter)); + } + } + + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_min = 0; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + { + return rotation_time; + } + return {rotation_time + std::chrono::minutes(1)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() + { + using details::os::filename_to_str; + using details::os::remove_if_exists; + + filename_t current_file = file_helper_.filename(); + if (filenames_q_.full()) + { + auto old_filename = std::move(filenames_q_.front()); + filenames_q_.pop_front(); + bool ok = remove_if_exists(old_filename) == 0; + if (!ok) + { + filenames_q_.push_back(std::move(current_file)); + SPDLOG_THROW(spdlog_ex("Failed removing minute file " + filename_to_str(old_filename), errno)); + } + } + filenames_q_.push_back(std::move(current_file)); + } + + filename_t base_filename_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; + uint16_t max_files_; + details::circular_q filenames_q_; + bool remove_init_file_; +}; + +using minute_file_sink_mt = minute_file_sink; +using minute_file_sink_st = minute_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr minute_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr minute_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); +} +} // namespace spdlog From 9d8efbde23d0404b56324b4351ccb7bf58a15dc5 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Thu, 4 May 2023 19:03:25 +0530 Subject: [PATCH 02/10] Review fixes Fixes as per suggestions --- include/spdlog/sinks/minute_file_sink.h | 31 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h index 26be135d7..24875447c 100644 --- a/include/spdlog/sinks/minute_file_sink.h +++ b/include/spdlog/sinks/minute_file_sink.h @@ -35,8 +35,8 @@ struct minute_filename_calculator { filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, - now_tm.tm_mday, now_tm.tm_hour,now_tm.tm_min,ext);//colock details define in os-inl.h + return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}-{:02d}_{:02d}{}")), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour,now_tm.tm_min,ext); } }; @@ -49,15 +49,23 @@ template class minute_file_sink final : public base_sink { public: - // create hourly file sink which rotates on given time + // create every minute file sink which rotates on given time minute_file_sink( - filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) + filename_t base_filename, bool truncate = false, uint16_t max_files = 0, + int rotation_minute = 0, const file_event_handlers &event_handlers = {}) : base_filename_(std::move(base_filename)) , file_helper_{event_handlers} , truncate_(truncate) , max_files_(max_files) + ,rotation_m_(rotation_minute) , filenames_q_() { + + if (rotation_minute < 0 || rotation_minute > 59) + { + throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); + } + auto now = log_clock::now(); auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); file_helper_.open(filename, truncate_); @@ -125,7 +133,7 @@ class minute_file_sink final : public base_sink break; } filenames.emplace_back(filename); - now -= std::chrono::minutes(1); + now -= std::chrono::minutes(rotation_m_); } for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) { @@ -143,14 +151,14 @@ class minute_file_sink final : public base_sink { auto now = log_clock::now(); tm date = now_tm(now); - date.tm_min = 0; + date.tm_sec = 0; auto rotation_time = log_clock::from_time_t(std::mktime(&date)); if (rotation_time > now) { return rotation_time; } - return {rotation_time + std::chrono::minutes(1)}; + return {rotation_time + std::chrono::minutes(rotation_m_)}; } // Delete the file N rotations ago. @@ -180,6 +188,7 @@ class minute_file_sink final : public base_sink details::file_helper file_helper_; bool truncate_; uint16_t max_files_; + int rotation_m_; details::circular_q filenames_q_; bool remove_init_file_; }; @@ -194,15 +203,15 @@ using minute_file_sink_st = minute_file_sink; // template inline std::shared_ptr minute_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) + uint16_t max_files = 0, int minute = 0, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); + return Factory::template create(logger_name, filename, truncate, max_files, minute ,event_handlers); } template inline std::shared_ptr minute_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) + uint16_t max_files = 0,int minute = 0, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); + return Factory::template create(logger_name, filename, truncate, max_files, minute, event_handlers); } } // namespace spdlog From 464013d95885dce996e0f29c416bc115ca3f5ef4 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Sun, 7 May 2023 12:48:31 +0530 Subject: [PATCH 03/10] Add files via upload Change the logger name to reflect the minutes interval based rotation and remove the check for max min 59 in configuration. --- include/spdlog/sinks/minute_file_sink.h | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h index 24875447c..539874b40 100644 --- a/include/spdlog/sinks/minute_file_sink.h +++ b/include/spdlog/sinks/minute_file_sink.h @@ -46,11 +46,11 @@ struct minute_filename_calculator * If max_files > 0, retain only the last max_files and delete previous. */ template -class minute_file_sink final : public base_sink +class minute_interval_file_sink final : public base_sink { public: // create every minute file sink which rotates on given time - minute_file_sink( + minute_interval_file_sink( filename_t base_filename, bool truncate = false, uint16_t max_files = 0, int rotation_minute = 0, const file_event_handlers &event_handlers = {}) : base_filename_(std::move(base_filename)) @@ -61,10 +61,7 @@ class minute_file_sink final : public base_sink , filenames_q_() { - if (rotation_minute < 0 || rotation_minute > 59) - { - throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); - } + auto now = log_clock::now(); auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); @@ -193,8 +190,8 @@ class minute_file_sink final : public base_sink bool remove_init_file_; }; -using minute_file_sink_mt = minute_file_sink; -using minute_file_sink_st = minute_file_sink; +using minute_interval_file_sink_mt = minute_interval_file_sink; +using minute_interval_file_sink_st = minute_interval_file_sink; } // namespace sinks @@ -202,16 +199,16 @@ using minute_file_sink_st = minute_file_sink; // factory functions // template -inline std::shared_ptr minute_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, +inline std::shared_ptr minute_interval_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0, int minute = 0, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, minute ,event_handlers); + return Factory::template create(logger_name, filename, truncate, max_files, minute ,event_handlers); } template -inline std::shared_ptr minute_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, +inline std::shared_ptr minute_interval_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0,int minute = 0, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, minute, event_handlers); + return Factory::template create(logger_name, filename, truncate, max_files, minute, event_handlers); } } // namespace spdlog From 526f938177ddea010a2e144ac0fd0ab85286730b Mon Sep 17 00:00:00 2001 From: mmanoj Date: Sun, 7 May 2023 12:56:51 +0530 Subject: [PATCH 04/10] Update check for 0 min configuration check. --- include/spdlog/sinks/minute_file_sink.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h index 539874b40..d5da1daa2 100644 --- a/include/spdlog/sinks/minute_file_sink.h +++ b/include/spdlog/sinks/minute_file_sink.h @@ -61,7 +61,10 @@ class minute_interval_file_sink final : public base_sink , filenames_q_() { - + if (rotation_minute < 0) + { + throw_spdlog_ex("minute_interval_file_sink: Invalid rotation time in ctor"); + } auto now = log_clock::now(); auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); From 16a946334dab31f5349eeb6e24213f6a92e10812 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Sun, 7 May 2023 13:01:49 +0530 Subject: [PATCH 05/10] corrected as rotation_minute <= 0 --- include/spdlog/sinks/minute_file_sink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h index d5da1daa2..b142922b7 100644 --- a/include/spdlog/sinks/minute_file_sink.h +++ b/include/spdlog/sinks/minute_file_sink.h @@ -61,7 +61,7 @@ class minute_interval_file_sink final : public base_sink , filenames_q_() { - if (rotation_minute < 0) + if (rotation_minute <= 0) { throw_spdlog_ex("minute_interval_file_sink: Invalid rotation time in ctor"); } From 9c141499b37857e19e63a83041927b3025f33135 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Sun, 7 May 2023 13:19:48 +0530 Subject: [PATCH 06/10] corrected as per suggestions --- include/spdlog/sinks/minute_file_sink.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h index b142922b7..d3901ab43 100644 --- a/include/spdlog/sinks/minute_file_sink.h +++ b/include/spdlog/sinks/minute_file_sink.h @@ -3,7 +3,7 @@ //File: minute_file_sink to support every 1 min file rotation. //Author Manoj Mallawaarachchie manoj_ws@yahoo.com / manoj@vizuamatix.com //example driver code: -//auto logger = spdlog::minute_logger_mt("minutes_basic_logger", "logs/min-log.txt",false,60); +//auto logger = spdlog::minute_interval_logger_mt("minute_interval_logger", "logs/min-log.txt",false,60); #pragma once @@ -203,14 +203,14 @@ using minute_interval_file_sink_st = minute_interval_file_sink inline std::shared_ptr minute_interval_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, int minute = 0, const file_event_handlers &event_handlers = {}) + uint16_t max_files = 0, int minute = 1, const file_event_handlers &event_handlers = {}) { return Factory::template create(logger_name, filename, truncate, max_files, minute ,event_handlers); } template inline std::shared_ptr minute_interval_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0,int minute = 0, const file_event_handlers &event_handlers = {}) + uint16_t max_files = 0,int minute = 1, const file_event_handlers &event_handlers = {}) { return Factory::template create(logger_name, filename, truncate, max_files, minute, event_handlers); } From 715414b7907b16233f300615e753e8d4230231a6 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Mon, 8 May 2023 10:36:02 +0530 Subject: [PATCH 07/10] Update as per comments Updated as per advice.Please check and update if any changes required. --- include/spdlog/sinks/periodic_file_sink.h | 216 ++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 include/spdlog/sinks/periodic_file_sink.h diff --git a/include/spdlog/sinks/periodic_file_sink.h b/include/spdlog/sinks/periodic_file_sink.h new file mode 100644 index 000000000..13868c061 --- /dev/null +++ b/include/spdlog/sinks/periodic_file_sink.h @@ -0,0 +1,216 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +//File: minute_file_sink to support every 1 min file rotation. +//example driver code: +//auto logger = spdlog::periodic_interval_logger_mt("minute_interval_logger", "logs/min-log.txt",false,60); + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * Generator of Minute log file names in format basename.YYYY-MM-DD-HH-MM.ext + */ +struct periodic_filename_calculator +{ + // Create filename for the form basename.YYYY-MM-DD-H-M + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}-{:02d}_{:02d}{}")), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour,now_tm.tm_min,ext); + } +}; + +/* + * Rotating file sink based on time(minutes). + * If truncate != false , the created file will be truncated. + * If max_files > 0, retain only the last max_files and delete previous. + */ +template +class periodic_interval_file_sink final : public base_sink +{ +public: + // create every periodic file sink which rotates on given time + periodic_interval_file_sink( + filename_t base_filename, bool truncate = false, uint16_t max_files = 0, + int rotation_period = 0, const file_event_handlers &event_handlers = {}) + : base_filename_(std::move(base_filename)) + , file_helper_{event_handlers} + , truncate_(truncate) + , max_files_(max_files) + ,rotation_m_(rotation_period) + , filenames_q_() + { + + if (rotation_period <= 0) + { + throw_spdlog_ex("periodic_interval_file_sink: Invalid rotation time in ctor"); + } + + auto now = log_clock::now(); + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + file_helper_.open(filename, truncate_); + remove_init_file_ = file_helper_.size() == 0; + rotation_tp_ = next_rotation_tp_(); + + if (max_files_ > 0) + { + init_filenames_q_(); + } + } + + filename_t filename() + { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + auto time = msg.time; + bool should_rotate = time >= rotation_tp_; + if (should_rotate) + { + if (remove_init_file_) + { + file_helper_.close(); + details::os::remove(file_helper_.filename()); + } + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + } + remove_init_file_ = false; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + + // Do the cleaning only at the end because it might throw on failure. + if (should_rotate && max_files_ > 0) + { + delete_old_(); + } + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + void init_filenames_q_() + { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) + { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) + { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::minutes(rotation_m_); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) + { + filenames_q_.push_back(std::move(*iter)); + } + } + + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + { + return rotation_time; + } + return {rotation_time + std::chrono::minutes(rotation_m_)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() + { + using details::os::filename_to_str; + using details::os::remove_if_exists; + + filename_t current_file = file_helper_.filename(); + if (filenames_q_.full()) + { + auto old_filename = std::move(filenames_q_.front()); + filenames_q_.pop_front(); + bool ok = remove_if_exists(old_filename) == 0; + if (!ok) + { + filenames_q_.push_back(std::move(current_file)); + SPDLOG_THROW(spdlog_ex("Failed removing periodic file " + filename_to_str(old_filename), errno)); + } + } + filenames_q_.push_back(std::move(current_file)); + } + + filename_t base_filename_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; + uint16_t max_files_; + int rotation_m_; + details::circular_q filenames_q_; + bool remove_init_file_; +}; + +using periodic_interval_file_sink_mt = periodic_interval_file_sink; +using periodic_interval_file_sink_st = periodic_interval_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr periodic_interval_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, int period = 1, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, max_files, period ,event_handlers); +} + +template +inline std::shared_ptr periodic_interval_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0,int period = 1, const file_event_handlers &event_handlers = {}) +{ + return Factory::template create(logger_name, filename, truncate, max_files, period, event_handlers); +} +} // namespace spdlog From 74a4eba4ffda18d6e0ada1fc36297a913931e2d4 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Mon, 8 May 2023 19:05:00 +0530 Subject: [PATCH 08/10] using std::chrono::duration using std::chrono::duration --- include/spdlog/sinks/periodic_file_sink.h | 37 ++++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/include/spdlog/sinks/periodic_file_sink.h b/include/spdlog/sinks/periodic_file_sink.h index 13868c061..6f03c4bfe 100644 --- a/include/spdlog/sinks/periodic_file_sink.h +++ b/include/spdlog/sinks/periodic_file_sink.h @@ -2,7 +2,8 @@ // Distributed under the MIT License (http://opensource.org/licenses/MIT) //File: minute_file_sink to support every 1 min file rotation. //example driver code: -//auto logger = spdlog::periodic_interval_logger_mt("minute_interval_logger", "logs/min-log.txt",false,60); +// auto duration{std::chrono::minutes{1}}; +//auto logger = spdlog::periodic_logger_mt("periodic_logger", "logs/min-log.txt",false,60,duration); #pragma once @@ -45,24 +46,24 @@ struct periodic_filename_calculator * If max_files > 0, retain only the last max_files and delete previous. */ template -class periodic_interval_file_sink final : public base_sink +class periodic_file_sink final : public base_sink { public: // create every periodic file sink which rotates on given time - periodic_interval_file_sink( + periodic_file_sink( filename_t base_filename, bool truncate = false, uint16_t max_files = 0, - int rotation_period = 0, const file_event_handlers &event_handlers = {}) + std::chrono::duration rotation_period = 0, const file_event_handlers &event_handlers = {}) : base_filename_(std::move(base_filename)) , file_helper_{event_handlers} , truncate_(truncate) , max_files_(max_files) - ,rotation_m_(rotation_period) + ,rotation_p_(rotation_period) , filenames_q_() { - if (rotation_period <= 0) + if (rotation_period <= std::chrono::minutes(0)) { - throw_spdlog_ex("periodic_interval_file_sink: Invalid rotation time in ctor"); + throw_spdlog_ex("periodic_file_sink: Invalid rotation time in ctor"); } auto now = log_clock::now(); @@ -132,7 +133,7 @@ class periodic_interval_file_sink final : public base_sink break; } filenames.emplace_back(filename); - now -= std::chrono::minutes(rotation_m_); + now -= rotation_p_; } for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) { @@ -157,7 +158,7 @@ class periodic_interval_file_sink final : public base_sink { return rotation_time; } - return {rotation_time + std::chrono::minutes(rotation_m_)}; + return {rotation_time + rotation_p_}; } // Delete the file N rotations ago. @@ -187,13 +188,13 @@ class periodic_interval_file_sink final : public base_sink details::file_helper file_helper_; bool truncate_; uint16_t max_files_; - int rotation_m_; + std::chrono::duration rotation_p_; details::circular_q filenames_q_; bool remove_init_file_; }; -using periodic_interval_file_sink_mt = periodic_interval_file_sink; -using periodic_interval_file_sink_st = periodic_interval_file_sink; +using periodic_file_sink_mt = periodic_file_sink; +using periodic_file_sink_st = periodic_file_sink; } // namespace sinks @@ -201,16 +202,16 @@ using periodic_interval_file_sink_st = periodic_interval_file_sink -inline std::shared_ptr periodic_interval_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, int period = 1, const file_event_handlers &event_handlers = {}) +inline std::shared_ptr periodic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, std::chrono::duration period = 1, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, period ,event_handlers); + return Factory::template create(logger_name, filename, truncate, max_files, period ,event_handlers); } template -inline std::shared_ptr periodic_interval_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0,int period = 1, const file_event_handlers &event_handlers = {}) +inline std::shared_ptr periodic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0,std::chrono::duration period = 1, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, period, event_handlers); + return Factory::template create(logger_name, filename, truncate, max_files, period, event_handlers); } } // namespace spdlog From 86daaf2575f4d9ca510f4e08e33d891bc2bccd62 Mon Sep 17 00:00:00 2001 From: mmanoj Date: Tue, 16 May 2023 09:25:31 +0530 Subject: [PATCH 09/10] Delete minute_file_sink.h --- include/spdlog/sinks/minute_file_sink.h | 217 ------------------------ 1 file changed, 217 deletions(-) delete mode 100644 include/spdlog/sinks/minute_file_sink.h diff --git a/include/spdlog/sinks/minute_file_sink.h b/include/spdlog/sinks/minute_file_sink.h deleted file mode 100644 index d3901ab43..000000000 --- a/include/spdlog/sinks/minute_file_sink.h +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -//File: minute_file_sink to support every 1 min file rotation. -//Author Manoj Mallawaarachchie manoj_ws@yahoo.com / manoj@vizuamatix.com -//example driver code: -//auto logger = spdlog::minute_interval_logger_mt("minute_interval_logger", "logs/min-log.txt",false,60); - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace spdlog { -namespace sinks { - -/* - * Generator of Minute log file names in format basename.YYYY-MM-DD-HH-MM.ext - */ -struct minute_filename_calculator -{ - // Create filename for the form basename.YYYY-MM-DD-H-M - static filename_t calc_filename(const filename_t &filename, const tm &now_tm) - { - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}-{:02d}_{:02d}{}")), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, - now_tm.tm_mday, now_tm.tm_hour,now_tm.tm_min,ext); - } -}; - -/* - * Rotating file sink based on time(minutes). - * If truncate != false , the created file will be truncated. - * If max_files > 0, retain only the last max_files and delete previous. - */ -template -class minute_interval_file_sink final : public base_sink -{ -public: - // create every minute file sink which rotates on given time - minute_interval_file_sink( - filename_t base_filename, bool truncate = false, uint16_t max_files = 0, - int rotation_minute = 0, const file_event_handlers &event_handlers = {}) - : base_filename_(std::move(base_filename)) - , file_helper_{event_handlers} - , truncate_(truncate) - , max_files_(max_files) - ,rotation_m_(rotation_minute) - , filenames_q_() - { - - if (rotation_minute <= 0) - { - throw_spdlog_ex("minute_interval_file_sink: Invalid rotation time in ctor"); - } - - auto now = log_clock::now(); - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); - file_helper_.open(filename, truncate_); - remove_init_file_ = file_helper_.size() == 0; - rotation_tp_ = next_rotation_tp_(); - - if (max_files_ > 0) - { - init_filenames_q_(); - } - } - - filename_t filename() - { - std::lock_guard lock(base_sink::mutex_); - return file_helper_.filename(); - } - -protected: - void sink_it_(const details::log_msg &msg) override - { - auto time = msg.time; - bool should_rotate = time >= rotation_tp_; - if (should_rotate) - { - if (remove_init_file_) - { - file_helper_.close(); - details::os::remove(file_helper_.filename()); - } - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); - file_helper_.open(filename, truncate_); - rotation_tp_ = next_rotation_tp_(); - } - remove_init_file_ = false; - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - file_helper_.write(formatted); - - // Do the cleaning only at the end because it might throw on failure. - if (should_rotate && max_files_ > 0) - { - delete_old_(); - } - } - - void flush_() override - { - file_helper_.flush(); - } - -private: - void init_filenames_q_() - { - using details::os::path_exists; - - filenames_q_ = details::circular_q(static_cast(max_files_)); - std::vector filenames; - auto now = log_clock::now(); - while (filenames.size() < max_files_) - { - auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); - if (!path_exists(filename)) - { - break; - } - filenames.emplace_back(filename); - now -= std::chrono::minutes(rotation_m_); - } - for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) - { - filenames_q_.push_back(std::move(*iter)); - } - } - - tm now_tm(log_clock::time_point tp) - { - time_t tnow = log_clock::to_time_t(tp); - return spdlog::details::os::localtime(tnow); - } - - log_clock::time_point next_rotation_tp_() - { - auto now = log_clock::now(); - tm date = now_tm(now); - - date.tm_sec = 0; - auto rotation_time = log_clock::from_time_t(std::mktime(&date)); - if (rotation_time > now) - { - return rotation_time; - } - return {rotation_time + std::chrono::minutes(rotation_m_)}; - } - - // Delete the file N rotations ago. - // Throw spdlog_ex on failure to delete the old file. - void delete_old_() - { - using details::os::filename_to_str; - using details::os::remove_if_exists; - - filename_t current_file = file_helper_.filename(); - if (filenames_q_.full()) - { - auto old_filename = std::move(filenames_q_.front()); - filenames_q_.pop_front(); - bool ok = remove_if_exists(old_filename) == 0; - if (!ok) - { - filenames_q_.push_back(std::move(current_file)); - SPDLOG_THROW(spdlog_ex("Failed removing minute file " + filename_to_str(old_filename), errno)); - } - } - filenames_q_.push_back(std::move(current_file)); - } - - filename_t base_filename_; - log_clock::time_point rotation_tp_; - details::file_helper file_helper_; - bool truncate_; - uint16_t max_files_; - int rotation_m_; - details::circular_q filenames_q_; - bool remove_init_file_; -}; - -using minute_interval_file_sink_mt = minute_interval_file_sink; -using minute_interval_file_sink_st = minute_interval_file_sink; - -} // namespace sinks - -// -// factory functions -// -template -inline std::shared_ptr minute_interval_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, int minute = 1, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, truncate, max_files, minute ,event_handlers); -} - -template -inline std::shared_ptr minute_interval_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0,int minute = 1, const file_event_handlers &event_handlers = {}) -{ - return Factory::template create(logger_name, filename, truncate, max_files, minute, event_handlers); -} -} // namespace spdlog From b1c1e4d165e3047c312655408552477115b0f76f Mon Sep 17 00:00:00 2001 From: mmanoj Date: Tue, 16 May 2023 12:25:10 +0530 Subject: [PATCH 10/10] Update as per comments --- include/spdlog/sinks/periodic_file_sink.h | 36 ++++++++++++++++------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/include/spdlog/sinks/periodic_file_sink.h b/include/spdlog/sinks/periodic_file_sink.h index 6f03c4bfe..2c8cff3b6 100644 --- a/include/spdlog/sinks/periodic_file_sink.h +++ b/include/spdlog/sinks/periodic_file_sink.h @@ -3,7 +3,7 @@ //File: minute_file_sink to support every 1 min file rotation. //example driver code: // auto duration{std::chrono::minutes{1}}; -//auto logger = spdlog::periodic_logger_mt("periodic_logger", "logs/min-log.txt",false,60,duration); +//auto logger = spdlog::periodic_logger_mt("periodic_logger", "logs/min-log.txt",duration,60,false); #pragma once @@ -50,18 +50,26 @@ class periodic_file_sink final : public base_sink { public: // create every periodic file sink which rotates on given time - periodic_file_sink( + /*periodic_file_sink( filename_t base_filename, bool truncate = false, uint16_t max_files = 0, std::chrono::duration rotation_period = 0, const file_event_handlers &event_handlers = {}) + + */ + periodic_file_sink( + filename_t base_filename, + std::chrono::minutes rotation_interval, + uint16_t max_files, + bool truncate_first = false, + const file_event_handlers &event_handlers = {}) : base_filename_(std::move(base_filename)) , file_helper_{event_handlers} - , truncate_(truncate) + , truncate_(truncate_first) , max_files_(max_files) - ,rotation_p_(rotation_period) + ,rotation_p_(rotation_interval) , filenames_q_() { - if (rotation_period <= std::chrono::minutes(0)) + if (rotation_interval <= std::chrono::minutes(0)) { throw_spdlog_ex("periodic_file_sink: Invalid rotation time in ctor"); } @@ -76,6 +84,12 @@ class periodic_file_sink final : public base_sink { init_filenames_q_(); } + + if (max_files > 2000) + { + throw_spdlog_ex("periodic_file_sink: max_files param exceeds max of 2000"); + } + } filename_t filename() @@ -202,16 +216,16 @@ using periodic_file_sink_st = periodic_file_sink; // factory functions // template -inline std::shared_ptr periodic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0, std::chrono::duration period = 1, const file_event_handlers &event_handlers = {}) +inline std::shared_ptr periodic_logger_mt(const std::string &logger_name, const filename_t &filename,std::chrono::minutes period = 1,uint16_t max_files = 0, bool truncate = false, + const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, period ,event_handlers); + return Factory::template create(logger_name, filename,period,max_files, truncate, event_handlers); } template -inline std::shared_ptr periodic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, - uint16_t max_files = 0,std::chrono::duration period = 1, const file_event_handlers &event_handlers = {}) +inline std::shared_ptr periodic_logger_st(const std::string &logger_name, const filename_t &filename,std::chrono::minutes period = 1,uint16_t max_files = 0, bool truncate = false, + const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files, period, event_handlers); + return Factory::template create(logger_name, filename,period, max_files,truncate, event_handlers); } } // namespace spdlog