added spdlog
This commit is contained in:
		| @@ -41,26 +41,9 @@ private: | ||||
| private: | ||||
|   event_level event_level_; | ||||
|   std::string log_directory_; | ||||
|   std::string log_path_; | ||||
|  | ||||
| private: | ||||
|   std::deque<std::shared_ptr<event>> event_queue_; | ||||
|   FILE *log_file_{nullptr}; | ||||
|   std::mutex log_mutex_; | ||||
|   std::condition_variable log_notify_; | ||||
|   bool logging_active_{true}; | ||||
|   std::unique_ptr<std::thread> logging_thread_; | ||||
|  | ||||
| private: | ||||
|   void check_log_roll(std::size_t count); | ||||
|  | ||||
|   void close_log_file(); | ||||
|  | ||||
|   void logging_thread(bool drain); | ||||
|  | ||||
|   void process_event(const event &event); | ||||
|  | ||||
|   void reopen_log_file(); | ||||
| }; | ||||
| } // namespace repertory | ||||
|  | ||||
|   | ||||
| @@ -21,158 +21,32 @@ | ||||
| */ | ||||
| #include "events/consumers/logging_consumer.hpp" | ||||
|  | ||||
| #include "events/events.hpp" | ||||
| #include "types/startup_exception.hpp" | ||||
| #include "utils/error_utils.hpp" | ||||
| #include "utils/file_utils.hpp" | ||||
| #include "utils/path_utils.hpp" | ||||
| #include "utils/unix/unix_utils.hpp" | ||||
| #include "utils/utils.hpp" | ||||
|  | ||||
| namespace repertory { | ||||
| logging_consumer::logging_consumer(event_level level, std::string log_directory) | ||||
|     : event_level_(level), | ||||
|       log_directory_(utils::path::absolute(log_directory)), | ||||
|       log_path_(utils::path::combine(log_directory, {"repertory.log"})) { | ||||
|   if (not utils::file::create_full_directory_path(log_directory_)) { | ||||
|     throw startup_exception("failed to create log directory|sp|" + | ||||
|                             log_directory_ + "|err|" + | ||||
|                             std::to_string(utils::get_last_error_code())); | ||||
|   } | ||||
|  | ||||
|   check_log_roll(0); | ||||
|   reopen_log_file(); | ||||
|       log_directory_(utils::path::absolute(log_directory)) { | ||||
|   E_SUBSCRIBE_ALL(process_event); | ||||
|   E_SUBSCRIBE_EXACT(event_level_changed, | ||||
|                     [this](const event_level_changed &changed) { | ||||
|                       event_level_ = event_level_from_string( | ||||
|                           changed.get_new_event_level().get<std::string>()); | ||||
|                     }); | ||||
|   logging_thread_ = | ||||
|       std::make_unique<std::thread>([this] { logging_thread(false); }); | ||||
| } | ||||
|  | ||||
| logging_consumer::~logging_consumer() { | ||||
|   E_CONSUMER_RELEASE(); | ||||
|  | ||||
|   unique_mutex_lock lock(log_mutex_); | ||||
|   logging_active_ = false; | ||||
|   log_notify_.notify_all(); | ||||
|   lock.unlock(); | ||||
|  | ||||
|   logging_thread_->join(); | ||||
|   logging_thread_.reset(); | ||||
|  | ||||
|   logging_thread(true); | ||||
|   close_log_file(); | ||||
| } | ||||
|  | ||||
| void logging_consumer::check_log_roll(std::size_t count) { | ||||
|   constexpr const auto *function_name = static_cast<const char *>(__FUNCTION__); | ||||
|  | ||||
|   std::uint64_t file_size{}; | ||||
|   auto success = utils::file::get_file_size(log_path_, file_size); | ||||
|   if (success && (file_size + count) >= MAX_LOG_FILE_SIZE) { | ||||
|     close_log_file(); | ||||
|     for (std::uint8_t i = MAX_LOG_FILES; i > 0u; i--) { | ||||
|       auto temp_log_path = utils::path::combine( | ||||
|           log_directory_, {"repertory." + std::to_string(i) + ".log"}); | ||||
|       if (utils::file::is_file(temp_log_path)) { | ||||
|         if (i == MAX_LOG_FILES) { | ||||
|           if (not utils::file::retry_delete_file(temp_log_path)) { | ||||
|             // TODO Handle error | ||||
|           } | ||||
|         } else { | ||||
|           auto next_file_path = utils::path::combine( | ||||
|               log_directory_, | ||||
|               {"repertory." + std::to_string(i + std::uint8_t(1)) + ".log"}); | ||||
|           if (not utils::file::move_file(temp_log_path, next_file_path)) { | ||||
|             utils::error::raise_error(function_name, | ||||
|                                       utils::get_last_error_code(), | ||||
|                                       temp_log_path + "|dest|" + next_file_path, | ||||
|                                       "failed to move file"); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     auto backup_log_path = | ||||
|         utils::path::combine(log_directory_, {"repertory.1.log"}); | ||||
|     if (not utils::file::move_file(log_path_, backup_log_path)) { | ||||
|       utils::error::raise_error(function_name, utils::get_last_error_code(), | ||||
|                                 log_path_ + "|dest|" + backup_log_path, | ||||
|                                 "failed to move file"); | ||||
|     } | ||||
|     reopen_log_file(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void logging_consumer::close_log_file() { | ||||
|   if (log_file_) { | ||||
|     fclose(log_file_); | ||||
|     log_file_ = nullptr; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void logging_consumer::logging_thread(bool drain) { | ||||
|   do { | ||||
|     std::deque<std::shared_ptr<event>> events; | ||||
|     { | ||||
|       unique_mutex_lock l(log_mutex_); | ||||
|       if (event_queue_.empty() && not drain) { | ||||
|         log_notify_.wait_for(l, 2s); | ||||
|       } else { | ||||
|         events.insert(events.end(), event_queue_.begin(), event_queue_.end()); | ||||
|         event_queue_.clear(); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     while (not events.empty()) { | ||||
|       auto event = events.front(); | ||||
|       events.pop_front(); | ||||
|  | ||||
|       if (event->get_event_level() <= event_level_) { | ||||
|         auto msg = ([&]() -> std::string { | ||||
|           struct tm local_time {}; | ||||
|           utils::get_local_time_now(local_time); | ||||
|  | ||||
|           std::stringstream ss; | ||||
|           ss << std::put_time(&local_time, "%F %T") << "|" | ||||
|              << event_level_to_string(event->get_event_level()).c_str() << "|" | ||||
|              << event->get_single_line().c_str() << std::endl; | ||||
|           return ss.str(); | ||||
|         })(); | ||||
|  | ||||
|         check_log_roll(msg.length()); | ||||
|         auto retry = true; | ||||
|         for (int i = 0; retry && (i < 2); i++) { | ||||
|           retry = (not log_file_ || (fwrite(msg.data(), 1, msg.length(), | ||||
|                                             log_file_) != msg.length())); | ||||
|           if (retry) { | ||||
|             reopen_log_file(); | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         if (log_file_) { | ||||
|           fflush(log_file_); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } while (logging_active_); | ||||
| } | ||||
| logging_consumer::~logging_consumer() { E_CONSUMER_RELEASE(); } | ||||
|  | ||||
| void logging_consumer::process_event(const event &event) { | ||||
|   mutex_lock lock(log_mutex_); | ||||
|   event_queue_.push_back(event.clone()); | ||||
|   log_notify_.notify_all(); | ||||
| } | ||||
|   /* auto msg = ([&]() -> std::string { | ||||
|     struct tm local_time {}; | ||||
|     utils::get_local_time_now(local_time); | ||||
|  | ||||
| void logging_consumer::reopen_log_file() { | ||||
|   close_log_file(); | ||||
| #if defined(_WIN32) | ||||
|   log_file_ = _fsopen(log_path_.c_str(), "a+", _SH_DENYWR); | ||||
| #else | ||||
|   log_file_ = fopen(log_path_.c_str(), "a+"); | ||||
| #endif | ||||
|     std::stringstream ss; | ||||
|     ss << std::put_time(&local_time, "%F %T") << "|" | ||||
|        << event_level_to_string(event->get_event_level()).c_str() << "|" | ||||
|        << event->get_single_line().c_str() << std::endl; | ||||
|     return ss.str(); | ||||
|   })(); */ | ||||
| } | ||||
| } // namespace repertory | ||||
|   | ||||
		Reference in New Issue
	
	Block a user