diff --git a/README.md b/README.md index 00e0ac29..d1f228c2 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,24 @@ $ export SPDLOG_LEVEL=info,mylogger=trace $ ./example ``` + +--- +#### Log file open/close event handlers +```c++ +// You can get subscribe to get callbacks from spdlog before/after log file has been opened or closed. +// This is useful for cleanup procedures or for adding someting the start/end of the log files. +void file_events_example() +{ + // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications + spdlog::file_event_handlers handlers; + handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); }; + handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("After opening\n", fstream); }; + handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("Before closing\n", fstream); }; + handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); }; + auto my_logger = spdlog::basic_logger_st("some_logger", "logs/events-sample.txt", true, handlers); +} +``` + --- ## Benchmarks diff --git a/example/example.cpp b/example/example.cpp index 56e28825..e379ca34 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -22,6 +22,7 @@ void err_handler_example(); void syslog_example(); void udp_example(); void custom_flags_example(); +void file_events_example(); #include "spdlog/spdlog.h" #include "spdlog/cfg/env.h" // support for loading levels from the environment variable @@ -78,6 +79,7 @@ int main(int, char *[]) stopwatch_example(); udp_example(); custom_flags_example(); + file_events_example(); // Flush all *registered* loggers using a worker thread every 3 seconds. // note: registered loggers *must* be thread safe for this to work correctly! @@ -120,22 +122,7 @@ void basic_example() void rotating_example() { // Create a file rotating logger with 5mb size max and 3 rotated files. - spdlog::file_event_handlers_t file_event_handlers; - file_event_handlers.after_open = [](spdlog::filename_t filename, std::FILE* fstream) - { - fputs("OPEN!\r\n", fstream); - spdlog::info("basic_example() : file_event_handlers.after_open : {}", filename.c_str()); - }; - file_event_handlers.before_close = [](spdlog::filename_t filename, std::FILE* fstream) - { - fputs("CLOSE!\r\n", fstream); - spdlog::info("basic_example() : file_event_handlers.before_close : {}", filename.c_str()); - }; - file_event_handlers.after_close = [](spdlog::filename_t filename) - { - spdlog::info("basic_example() : file_event_handlers.after_close : {}", filename.c_str()); - }; - auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3, false, file_event_handlers); + auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); } #include "spdlog/sinks/daily_file_sink.h" @@ -317,5 +304,25 @@ void custom_flags_example() using spdlog::details::make_unique; // for pre c++14 auto formatter = make_unique(); formatter->add_flag('*').set_pattern("[%n] [%*] [%^%l%$] %v"); - spdlog::set_formatter(std::move(formatter)); + // set the new formatter using spdlog::set_formatter(formatter) or logger->set_formatter(formatter) + // spdlog::set_formatter(std::move(formatter)); +} + +void file_events_example() +{ + // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications + spdlog::file_event_handlers handlers; + handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); }; + handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { + spdlog::info("After opening {}", filename); + fputs("After opening\n", fstream); + }; + handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { + spdlog::info("Before closing {}", filename); + fputs("Before closing\n", fstream); + }; + handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); }; + auto file_sink = std::make_shared("logs/events-sample.txt", true, handlers); + spdlog::logger my_logger("some_logger", file_sink); + my_logger.info("Some log line"); } diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 0d170412..40bac3e6 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -302,12 +302,13 @@ struct source_loc const char *funcname{nullptr}; }; -typedef struct +struct file_event_handlers { + std::function before_open; std::function after_open; std::function before_close; std::function after_close; -} file_event_handlers_t; +}; namespace details { // make_unique support for pre c++14 diff --git a/include/spdlog/details/file_helper-inl.h b/include/spdlog/details/file_helper-inl.h index df6cd4c1..63d511c6 100644 --- a/include/spdlog/details/file_helper-inl.h +++ b/include/spdlog/details/file_helper-inl.h @@ -20,7 +20,7 @@ namespace spdlog { namespace details { -SPDLOG_INLINE file_helper::file_helper(const file_event_handlers_t& event_handlers) +SPDLOG_INLINE file_helper::file_helper(const file_event_handlers& event_handlers) : event_handlers_(event_handlers) {} @@ -37,6 +37,10 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) auto *mode = SPDLOG_FILENAME_T("ab"); auto *trunc_mode = SPDLOG_FILENAME_T("wb"); + if (event_handlers_.before_open) + { + event_handlers_.before_open(filename_); + } for (int tries = 0; tries < open_tries_; ++tries) { // create containing folder if not exists already. diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 60c47788..69c5afdc 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -17,7 +17,7 @@ class SPDLOG_API file_helper { public: file_helper() = default; - explicit file_helper(const file_event_handlers_t& event_handlers); + explicit file_helper(const file_event_handlers& event_handlers); file_helper(const file_helper &) = delete; file_helper &operator=(const file_helper &) = delete; @@ -51,7 +51,7 @@ private: const unsigned int open_interval_ = 10; std::FILE *fd_{nullptr}; filename_t filename_; - file_event_handlers_t event_handlers_{nullptr, nullptr, nullptr}; + file_event_handlers event_handlers_; }; } // namespace details } // namespace spdlog diff --git a/include/spdlog/sinks/basic_file_sink-inl.h b/include/spdlog/sinks/basic_file_sink-inl.h index 463e075f..af383214 100644 --- a/include/spdlog/sinks/basic_file_sink-inl.h +++ b/include/spdlog/sinks/basic_file_sink-inl.h @@ -14,7 +14,7 @@ namespace spdlog { namespace sinks { template -SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers_t& event_handlers) +SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers& event_handlers) : file_helper_{event_handlers} { file_helper_.open(filename, truncate); diff --git a/include/spdlog/sinks/basic_file_sink.h b/include/spdlog/sinks/basic_file_sink.h index 51e26e38..12cd95ef 100644 --- a/include/spdlog/sinks/basic_file_sink.h +++ b/include/spdlog/sinks/basic_file_sink.h @@ -20,7 +20,7 @@ template class basic_file_sink final : public base_sink { public: - explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}); + explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers& event_handlers = {}); const filename_t &filename() const; protected: @@ -40,13 +40,13 @@ using basic_file_sink_st = basic_file_sink; // factory functions // template -inline std::shared_ptr basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) +inline std::shared_ptr basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, truncate, event_handlers); } template -inline std::shared_ptr basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) +inline std::shared_ptr basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, truncate, event_handlers); } diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h index 36701e98..c0f896a1 100644 --- a/include/spdlog/sinks/daily_file_sink.h +++ b/include/spdlog/sinks/daily_file_sink.h @@ -116,7 +116,7 @@ class daily_file_sink final : public base_sink { public: // create daily file sink which rotates on given time - daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0, const file_event_handlers& event_handlers = {}) : base_filename_(std::move(base_filename)) , rotation_h_(rotation_hour) , rotation_m_(rotation_minute) @@ -263,28 +263,28 @@ using daily_file_format_sink_st = daily_file_sink inline std::shared_ptr daily_logger_mt( - const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); } template inline std::shared_ptr daily_logger_format_mt( - const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); } template inline std::shared_ptr daily_logger_st( - const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); } template inline std::shared_ptr daily_logger_format_st( - const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); } diff --git a/include/spdlog/sinks/hourly_file_sink.h b/include/spdlog/sinks/hourly_file_sink.h index 71b5a1b4..7a7c715c 100644 --- a/include/spdlog/sinks/hourly_file_sink.h +++ b/include/spdlog/sinks/hourly_file_sink.h @@ -46,7 +46,7 @@ class hourly_file_sink final : public base_sink { public: // create hourly file sink which rotates on given time - hourly_file_sink(filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + hourly_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) @@ -181,14 +181,14 @@ using hourly_file_sink_st = hourly_file_sink; // template inline std::shared_ptr hourly_logger_mt( - const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + 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 hourly_logger_st( - const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + 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); } diff --git a/include/spdlog/sinks/rotating_file_sink-inl.h b/include/spdlog/sinks/rotating_file_sink-inl.h index 87e80593..8555d0d2 100644 --- a/include/spdlog/sinks/rotating_file_sink-inl.h +++ b/include/spdlog/sinks/rotating_file_sink-inl.h @@ -25,7 +25,7 @@ namespace sinks { template SPDLOG_INLINE rotating_file_sink::rotating_file_sink( - filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open, const file_event_handlers_t& event_handlers) + filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open, const file_event_handlers& event_handlers) : base_filename_(std::move(base_filename)) , max_size_(max_size) , max_files_(max_files) diff --git a/include/spdlog/sinks/rotating_file_sink.h b/include/spdlog/sinks/rotating_file_sink.h index 8455227f..d34ec02e 100644 --- a/include/spdlog/sinks/rotating_file_sink.h +++ b/include/spdlog/sinks/rotating_file_sink.h @@ -22,7 +22,7 @@ template class rotating_file_sink final : public base_sink { public: - rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}); + rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false, const file_event_handlers& event_handlers = {}); static filename_t calc_filename(const filename_t &filename, std::size_t index); filename_t filename(); @@ -60,14 +60,14 @@ using rotating_file_sink_st = rotating_file_sink; template inline std::shared_ptr rotating_logger_mt( - const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); } template inline std::shared_ptr rotating_logger_st( - const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false, const file_event_handlers_t& event_handlers = {nullptr, nullptr, nullptr}) + const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false, const file_event_handlers& event_handlers = {}) { return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); }